+# in general it's right to rely on the contents as reported by git
tags:
git ls-files | xargs etags
+
+# however sometimes we have stuff not yet added, so in this case
+ftags:
+ find . -type f | fgrep -v '/.git/' | xargs etags
--- /dev/null
+Metadata-Version: 1.0
+Name: django-insert-above
+Version: 1.0.4
+Summary: These django templatetags is a hack making possible to insert "content" in some (maybe above the current or parent template) places.
+Home-page: https://github.com/yunmanger1/django-insert-above/
+Author: German Ilyin
+Author-email: germanilyin@gmail.com
+License: WTFPL
+Description: WHAT IS IT?
+ -----------
+
+ These templatetags is a hack making possible to insert 'content' in
+ some (maybe above the current or parent template) places.
+
+ More specifically, when we use these tags, there are some Nodes called
+ 'containers' that are rendered after all other nodes are rendered, but placed
+ in it's right posistion. Using this hack, 'containers' may render
+ depending on variables in context that were generated by nodes placed anywhere in
+ template (maybe after it).
+
+ It's very useful in cases when you are reusing some template parts
+ very often. For example displaying comment list and comment submit form.
+ We write some template and put it into comments.html. Then every time
+ we need comments we just {% include "comments.html" %}.
+ But what if this part needs some js or css? Then we need to create
+ some comments-jscss.html and override some {% block head %}. IMHO this
+ is quite inconvenient.
+
+ Using this tool we can insert js and css into head
+ directly from comments.html
+
+ MOTIVATION
+ ----------
+
+ 1. Create convenient way to include media resources in head of HTML page.
+ 2. Handle repetition of resource includes.
+ 3. Make it possible to require resources from included templates.
+ 4. Keep the order of resource includes from different places.
+
+ INSTALL
+ -------
+
+ 1. (required) add 'insert_above' in INSTALLED_APPS in your settings.py
+
+ 2. (optional) add these two lines of code somewhere in your project where
+ they will run for sure. For example in urls.py
+
+ ~~~~
+ from django.template.loader import add_to_builtins
+ add_to_builtins('insert_above.templatetags.insert_tags')
+ ~~~~
+
+ TAGS & FILTERS
+ --------------
+
+ 1. {% insert_handler %}
+ 2. {% container name %}
+ 3. {% media_container name %}
+ 4. {% insert_str container str %}
+ 5. {% insert container %}{% endinsert %}
+ 6. media_tag filter simply converts `ga.js` into `<script type='text/javascript' src='/static/ga.js'></script>`
+
+ RESTRICTIONS
+ ------------
+
+ 1. `{% container %}` or `{% media_container %}` tags must NOT be in other `{% block %}`.
+ 2. `{% insert_handler %}` ought to be at ther very beginning of base template.
+
+ VARIABLES
+ ---------
+
+ 1. `IA_USE_MEDIA_PREFIX`, by default True
+ 2. `IA_MEDIA_PREFIX`, if not set `STATIC_URL` is used, if not set `MEDIA_URL` is used, if not set '/media/' is used
+ 3. `DEBUG`, if True logs how much time spent on rendering
+ 4. `IA_JS_FORMAT`, by default `<script type='text/javascript' src='{URL}'></script>`
+ 5. `IA_CSS_FORMAT`, by default `<link rel='stylesheet' href='{URL}' type='text/css' />`
+ 6. `IA_MEDIA_EXTENSION_FORMAT_MAP`, by default `{'css' : CSS_FORMAT, '.js' : JS_FORMAT}`
+
+ EXAMPLE
+ -------
+
+ Let's analyze an example.
+
+ base.html
+
+ ~~~~{.html}
+ {% insert_handler %}
+ <html>
+ <head>
+ <script>
+ <script type='text/javascript' src='{{ MEDIA_URL }}js/jquery.min.js'></script>
+ {% media_container media %}
+
+ $(document).ready(function(){
+ {% container ready %}
+ });
+ </script>
+ </head>
+ <body>
+ {% block content %}
+ {% endblock %}
+ </body>
+ </html>
+ ~~~~
+
+ Base template creating blocks and containers..
+
+ blog/base.html
+
+ ~~~~{.html}
+ {% extends "base.html" %}
+
+ {% block content %}
+ {% insert_str media "js/mathjax.js" %}
+ {% block header %}{% endblock %}
+ {% block menu %}{% include "blog/menu.html" %}{% endblock %}
+ {% block text %}{% endblock %}
+ {% block footer %}{% endblock %}
+ {% endblock %}
+ ~~~~
+
+ Extending content block. Requiring js/mathjax.js resource into 'media' container.
+
+ blog/menu.html
+
+ ~~~~{.html}
+ {% insert_str media "js/animated.menu.js" %}
+ {% insert_str media "css/animated.menu.css" %}
+ {% insert ready %}
+ $('ul.menu').each(function(){
+ $(this).superanimation();
+ });
+ {% endinsert %}
+ <ul id='blog-menu' class='menu'>
+ <li>link</li>
+ <li>link</li>
+ <li>link</li>
+ </ul>
+ ~~~~
+
+ Requiring js/animated.menu.js and css/animated.menu.css into "media" container.
+ Inserting javascript code into "ready" container.
+
+ blog/post_detail.html
+
+ ~~~~{.html}
+ {% extends "blog/base.html" %}
+
+ {% block header %}{{ title }}{% endblock %}
+
+ {% block text %}
+ {% insert_str media "js/mathjax.js" %}
+ {{ text }}
+ {% endblock %}
+
+ {% block footer %}
+ <hr>
+ {% endblock %}
+ ~~~~
+
+ Implementing blocks and requiring js/mathjax.js into media.
+
+
+ So if we render
+ Template('blog/post_detail.html').render(Context({'title': 'Hello', 'text': 'World'}))
+ we will get:
+
+ ~~~~{.html}
+ <html>
+ <head>
+ <script>
+ <script type='text/javascript' src='/media/js/jquery.min.js'></script>
+ <script type='text/javascript' src='/media/js/mathjax.js'></script>
+ <script type='text/javascript' src='/media/js/animated.menu.js'></script>
+ <link rel="stylesheet" href="/media/css/animated.menu.css" type="text/css" />
+
+ $(document).ready(function(){
+ $('ul.menu').each(function(){
+ $(this).superanimation();
+ });
+ });
+ </script>
+ </head>
+ <body>
+ Hello
+ <ul id='blog-menu' class='menu'>
+ <li>link</li>
+ <li>link</li>
+ <li>link</li>
+ </ul>
+ World
+ <hr>
+ </body>
+ </html>
+ ~~~~
+
+ What shall be noted?
+ -------------------
+
+ 1. `js/mathjax.js` automatically becomes `<script type='text/javascript' src='/media/js/mathjax.js'></script>`
+ and `css/animated.menu.css` becomes `<link rel="stylesheet" href="/media/css/animated.menu.css" type="text/css" />`
+ 2. inserting from included template is possible
+ 3. any text may be inserted to any container. Here we insert javascript code in `$(document).ready(function(){});`
+ 4. `js/mathjax.js` was required twice, but included only once.
+ 5. The order of included resources is kept.
+
+ FIXTURES
+ --------
+
+ ### version 1.0.2
+
+ + **fix MEDIA_URL setting**
+ if STATIC_URL is not set in settings, it's value is None by default in new versions of Django.
+ Now we check if STATIC_URL is None, then use MEDIA_URL
+
+ ### version 1.0.4
+
+ + added new tag `{% insert_form container form %}`
+ + added new tag `{% insert_form container form.media %}`
+
+ ## TODOs
+
+ 1. testing
+ 2. extending tags
+ 3. resource bulking
+
+
+Platform: UNKNOWN
+Classifier: Development Status :: 3 - Alpha
+Classifier: Topic :: Utilities
+Classifier: Environment :: Plugins
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: License :: Freeware
+Classifier: Programming Language :: Python :: 2.6
--- /dev/null
+WHAT IS IT?
+-----------
+
+These templatetags is a hack making possible to insert 'content' in
+some (maybe above the current or parent template) places.
+
+More specifically, when we use these tags, there are some Nodes called
+'containers' that are rendered after all other nodes are rendered, but placed
+in it's right posistion. Using this hack, 'containers' may render
+depending on variables in context that were generated by nodes placed anywhere in
+template (maybe after it).
+
+It's very useful in cases when you are reusing some template parts
+very often. For example displaying comment list and comment submit form.
+We write some template and put it into comments.html. Then every time
+we need comments we just {% include "comments.html" %}.
+But what if this part needs some js or css? Then we need to create
+some comments-jscss.html and override some {% block head %}. IMHO this
+is quite inconvenient.
+
+Using this tool we can insert js and css into head
+directly from comments.html
+
+MOTIVATION
+----------
+
+1. Create convenient way to include media resources in head of HTML page.
+2. Handle repetition of resource includes.
+3. Make it possible to require resources from included templates.
+4. Keep the order of resource includes from different places.
+
+INSTALL
+-------
+
+1. (required) add 'insert_above' in INSTALLED_APPS in your settings.py
+
+2. (optional) add these two lines of code somewhere in your project where
+they will run for sure. For example in urls.py
+
+~~~~
+from django.template.loader import add_to_builtins
+add_to_builtins('insert_above.templatetags.insert_tags')
+~~~~
+
+TAGS & FILTERS
+--------------
+
+1. {% insert_handler %}
+2. {% container name %}
+3. {% media_container name %}
+4. {% insert_str container str %}
+5. {% insert container %}{% endinsert %}
+6. media_tag filter simply converts `ga.js` into `<script type='text/javascript' src='/static/ga.js'></script>`
+
+RESTRICTIONS
+------------
+
+1. `{% container %}` or `{% media_container %}` tags must NOT be in other `{% block %}`.
+2. `{% insert_handler %}` ought to be at ther very beginning of base template.
+
+VARIABLES
+---------
+
+1. `IA_USE_MEDIA_PREFIX`, by default True
+2. `IA_MEDIA_PREFIX`, if not set `STATIC_URL` is used, if not set `MEDIA_URL` is used, if not set '/media/' is used
+3. `DEBUG`, if True logs how much time spent on rendering
+4. `IA_JS_FORMAT`, by default `<script type='text/javascript' src='{URL}'></script>`
+5. `IA_CSS_FORMAT`, by default `<link rel='stylesheet' href='{URL}' type='text/css' />`
+6. `IA_MEDIA_EXTENSION_FORMAT_MAP`, by default `{'css' : CSS_FORMAT, '.js' : JS_FORMAT}`
+
+EXAMPLE
+-------
+
+Let's analyze an example.
+
+base.html
+
+~~~~{.html}
+{% insert_handler %}
+<html>
+<head>
+<script>
+<script type='text/javascript' src='{{ MEDIA_URL }}js/jquery.min.js'></script>
+{% media_container media %}
+
+$(document).ready(function(){
+{% container ready %}
+});
+</script>
+</head>
+<body>
+{% block content %}
+{% endblock %}
+</body>
+</html>
+~~~~
+
+Base template creating blocks and containers..
+
+blog/base.html
+
+~~~~{.html}
+{% extends "base.html" %}
+
+{% block content %}
+{% insert_str media "js/mathjax.js" %}
+ {% block header %}{% endblock %}
+ {% block menu %}{% include "blog/menu.html" %}{% endblock %}
+ {% block text %}{% endblock %}
+ {% block footer %}{% endblock %}
+{% endblock %}
+~~~~
+
+Extending content block. Requiring js/mathjax.js resource into 'media' container.
+
+blog/menu.html
+
+~~~~{.html}
+{% insert_str media "js/animated.menu.js" %}
+{% insert_str media "css/animated.menu.css" %}
+{% insert ready %}
+ $('ul.menu').each(function(){
+ $(this).superanimation();
+ });
+{% endinsert %}
+<ul id='blog-menu' class='menu'>
+ <li>link</li>
+ <li>link</li>
+ <li>link</li>
+</ul>
+~~~~
+
+Requiring js/animated.menu.js and css/animated.menu.css into "media" container.
+Inserting javascript code into "ready" container.
+
+blog/post_detail.html
+
+~~~~{.html}
+{% extends "blog/base.html" %}
+
+{% block header %}{{ title }}{% endblock %}
+
+{% block text %}
+{% insert_str media "js/mathjax.js" %}
+{{ text }}
+{% endblock %}
+
+{% block footer %}
+<hr>
+{% endblock %}
+~~~~
+
+Implementing blocks and requiring js/mathjax.js into media.
+
+
+So if we render
+Template('blog/post_detail.html').render(Context({'title': 'Hello', 'text': 'World'}))
+we will get:
+
+~~~~{.html}
+<html>
+<head>
+<script>
+<script type='text/javascript' src='/media/js/jquery.min.js'></script>
+<script type='text/javascript' src='/media/js/mathjax.js'></script>
+<script type='text/javascript' src='/media/js/animated.menu.js'></script>
+<link rel="stylesheet" href="/media/css/animated.menu.css" type="text/css" />
+
+$(document).ready(function(){
+ $('ul.menu').each(function(){
+ $(this).superanimation();
+ });
+});
+</script>
+</head>
+<body>
+Hello
+<ul id='blog-menu' class='menu'>
+ <li>link</li>
+ <li>link</li>
+ <li>link</li>
+</ul>
+World
+<hr>
+</body>
+</html>
+~~~~
+
+What shall be noted?
+-------------------
+
+1. `js/mathjax.js` automatically becomes `<script type='text/javascript' src='/media/js/mathjax.js'></script>`
+and `css/animated.menu.css` becomes `<link rel="stylesheet" href="/media/css/animated.menu.css" type="text/css" />`
+2. inserting from included template is possible
+3. any text may be inserted to any container. Here we insert javascript code in `$(document).ready(function(){});`
+4. `js/mathjax.js` was required twice, but included only once.
+5. The order of included resources is kept.
+
+FIXTURES
+--------
+
+### version 1.0.2
+
+ + **fix MEDIA_URL setting**
+ if STATIC_URL is not set in settings, it's value is None by default in new versions of Django.
+ Now we check if STATIC_URL is None, then use MEDIA_URL
+
+### version 1.0.4
+
+ + added new tag `{% insert_form container form %}`
+ + added new tag `{% insert_form container form.media %}`
+
+## TODOs
+
+1. testing
+2. extending tags
+3. resource bulking
+
--- /dev/null
+#!/usr/bin/env python
+import os
+from distutils.core import setup
+
+def read(fname):
+ return open(os.path.join(os.path.dirname(__file__), fname)).read()
+
+setup(name = 'django-insert-above',
+ version = '1.0.4',
+ description = 'These django templatetags is a hack making possible to insert "content" in some (maybe above the current or parent template) places.',
+ author = 'German Ilyin',
+ author_email = 'germanilyin@gmail.com',
+ url = 'https://github.com/yunmanger1/django-insert-above/',
+ license = 'WTFPL',
+ long_description = read('README'),
+ packages = ['insert_above', 'insert_above.templatetags'],
+ classifiers = [
+ "Development Status :: 3 - Alpha",
+ "Topic :: Utilities",
+ "Environment :: Plugins",
+ "Framework :: Django",
+ "Intended Audience :: Developers",
+ "License :: Freeware",
+ "Programming Language :: Python :: 2.6",
+ ],
+)
==================== postinstall
. manage.py syncdb
. manage.py collectstatic --noinput
+
+======================================== django-insert-above
+this package was downloaded in source doce from github and installed
+as-is as insert_above, and enabled as the README has it
+
+========================================
--- /dev/null
+"""
+This program is free software. It comes without any warranty, to
+the extent permitted by applicable law. You can redistribute it
+and/or modify it under the terms of the Do What The Fuck You Want
+To Public License, Version 2, as published by Sam Hocevar. See
+http://sam.zoy.org/wtfpl/COPYING for more details.
+"""
+
+from django import template
+from django.conf import settings
+from django.template import loader_tags
+from django.utils.encoding import force_unicode
+from django.utils.safestring import mark_safe
+import time
+from django.template.base import Variable
+from django import forms
+from django.utils.datastructures import SortedDict
+register = template.Library()
+
+try:
+ from common import logwrapper
+ log = logwrapper.defaultLogger(__file__)
+except ImportError:
+ import logging
+ log = logging.getLogger(__name__)
+
+INSERT_TAG_KEY = 'insert-demands'
+DEBUG = getattr(settings, 'IA_DEBUG', False)
+MEDIA_URL = getattr(settings, 'IA_MEDIA_PREFIX', None)
+if MEDIA_URL is None:
+ MEDIA_URL = getattr(settings, 'STATIC_URL', None)
+if MEDIA_URL is None:
+ MEDIA_URL = getattr(settings, 'MEDIA_URL', None)
+if MEDIA_URL is None:
+ MEDIA_URL = '/media/'
+USE_MEDIA_PREFIX = getattr(settings, 'IA_USE_MEDIA_PREFIX', True)
+JS_FORMAT = getattr(settings, 'IA_JS_FORMAT', "<script type='text/javascript' src='{URL}'></script>")
+CSS_FORMAT = getattr(settings, 'IA_CSS_FORMAT', "<link rel='stylesheet' href='{URL}' type='text/css' />")
+
+if hasattr(settings, 'IA_MEDIA_EXTENSION_FORMAT_MAP'):
+ MEDIA_EXTENSION_FORMAT_MAP = settings.IA_MEDIA_EXTENSION_FORMAT_MAP
+else:
+ # by convention key must be 3 characters length. This helps to optimize lookup process
+ MEDIA_EXTENSION_FORMAT_MAP = {
+ 'css' : CSS_FORMAT,
+ '.js' : JS_FORMAT,
+ }
+
+def render_media(extension, ctx):
+ """
+ Renders media format. Used in media container.
+ """
+ fmt = MEDIA_EXTENSION_FORMAT_MAP[extension]
+ return fmt.format(**ctx)
+
+def get_from_context_root(context, KEY):
+ """
+ Gets or creates dictinoary in root context.
+ """
+ if not KEY in context.dicts[0]:
+ context.dicts[0].update({KEY : {}})
+ return context.dicts[0].get(KEY)
+
+def add_render_time(context, dt):
+ """
+ Adds value to root context, which will be used
+ later in insert handler node.
+ """
+ cache = get_from_context_root(context, INSERT_TAG_KEY)
+ t = cache.get('DEBUG_TIME', 0) + dt
+ cache.update({'DEBUG_TIME': t})
+
+def get_render_time(context):
+ cache = get_from_context_root(context, INSERT_TAG_KEY)
+ t = cache.get('DEBUG_TIME', 0)
+ return t
+
+def consider_time(f):
+ """
+ Decorator used to calculate
+ how much time was spent on rendering
+ "insert_above" tags.
+ """
+ def nf(obj, context, *args, **kwargs):
+ t = time.time()
+ result = f(obj, context, *args, **kwargs)
+ dt = time.time() - t
+ add_render_time(context, dt)
+ return result
+ if DEBUG:
+ return nf
+ return f
+
+class OrderedItem(object):
+ """
+ String items all over the templates must be
+ rendered in the same order they were encountered.
+ """
+ order = 0
+
+ def __init__(self, item):
+ cur = OrderedItem.order
+ self.item, self.order = item, cur
+ OrderedItem.order = cur + 1
+
+ def __cmp__(self, o):
+ if self.item == o.item:
+ return 0
+ return self.order - o.order
+
+ def __unicode__(self):
+ return self.item
+
+ def __hash__(self):
+ return self.item.__hash__()
+
+ def __str__(self):
+ return self.__unicode__()
+
+class InsertHandlerNode(template.Node):
+ #must_be_first = True
+
+ def __init__(self, nodelist, *args, **kwargs):
+ super(InsertHandlerNode, self).__init__(*args, **kwargs)
+ self.nodelist = nodelist
+ self.blocks = dict([(n.name, n) for n in nodelist.get_nodes_by_type(template.loader_tags.BlockNode)])
+
+ def __repr__(self):
+ return '<MediaHandlerNode>'
+
+ def render_nodelist(self, nodelist, context):
+ bits = []
+ medias = []
+ index = 0
+ for node in nodelist:
+ if isinstance(node, ContainerNode):
+ node.index = index
+ bits.append('')
+ medias.append(node)
+ elif isinstance(node, template.Node):
+ bits.append(nodelist.render_node(node, context))
+ else:
+ bits.append(node)
+ index += 1
+ for node in medias:
+ bits[node.index] = nodelist.render_node(node, context)
+ if DEBUG:
+ log.debug("spent {0:.6f} ms on insert_tags".format(get_render_time(context)))
+ return mark_safe(''.join([force_unicode(b) for b in bits]))
+
+ def render(self, context):
+ if loader_tags.BLOCK_CONTEXT_KEY not in context.render_context:
+ context.render_context[loader_tags.BLOCK_CONTEXT_KEY] = loader_tags.BlockContext()
+ block_context = context.render_context[loader_tags.BLOCK_CONTEXT_KEY]
+
+ # Add the block nodes from this node to the block context
+ block_context.add_blocks(self.blocks)
+ return self.render_nodelist(self.nodelist, context)
+# return self.nodelist.render(context)
+
+class InsertNode(template.Node):
+ def __init__(self, container_name, insert_string = None, subnodes = None, *args, **kwargs):
+ """
+ Note: `self.container_name, self.insert_line, self.subnodes` must not be changed during
+ `render()` call. Method `render()` may be called multiple times.
+ """
+ super(InsertNode, self).__init__(*args, **kwargs)
+ self.container_name, self.insert_line, self.subnodes = container_name, insert_string, subnodes
+ self.index = None
+ self.prev_context_hash = None
+
+ def __repr__(self):
+ return "<Media Require Node: %s>" % (self.insert_line)
+
+ def push_media(self, context):
+ if self.prev_context_hash == context.__hash__():
+ if DEBUG:
+ log.debug('same context: {0} == {1}'.format(self.prev_context_hash, context.__hash__()))
+ return
+ self.prev_context_hash = context.__hash__()
+ cache = get_from_context_root(context, INSERT_TAG_KEY)
+ reqset = cache.get(self.container_name, None)
+ if not reqset:
+ reqset = []
+ cache[self.container_name] = reqset
+ insert_content = None
+ if self.insert_line == None:
+ if self.subnodes == None:
+ raise AttributeError('insert_line or subnodes must be specified')
+ insert_content = self.subnodes.render(context)
+ else:
+ if self.subnodes != None:
+ raise AttributeError('insert_line or subnodes must be specified, not both')
+ var = True
+ insert_content = Variable(self.insert_line).resolve(context)
+ reqset.append(OrderedItem(insert_content))
+
+ @consider_time
+ def render(self, context):
+ self.push_media(context)
+ return ''
+
+class ContainerNode(template.Node):
+ def __init__(self, name, *args, **kwargs):
+ super(ContainerNode, self).__init__(*args, **kwargs)
+ self.name = name
+
+ def __repr__(self):
+ return "<Container Node: %s>" % (self.name)
+
+ @consider_time
+ def render(self, context):
+ reqset = get_from_context_root(context, INSERT_TAG_KEY).get(self.name, None)
+ if not reqset:
+ return ''
+ items = reqset
+ #items.sort()
+ return "\n".join([x.__unicode__() for x in items])
+
+def media_tag(url, **kwargs):
+ """
+ Usage: {{ url|media_tag }}
+ Simply wraps media url into appropriate HTML tag.
+
+ Example: {{ "js/ga.js"|media_tag }}
+ The result will be <script type='text/javascript' src='/static/js/ga.js'></script>
+
+ Last 3 characters of url define which
+ format string from MEDIA_EXTENSION_FORMAT_MAP will be used.
+ """
+
+ url = url.split('\n')[0].strip()
+ ext = url[-3:]
+ full = url.startswith('http://') or url.startswith('https://')
+ if USE_MEDIA_PREFIX and not full:
+ link = '{0}{1}'.format(MEDIA_URL, url)
+ else:
+ link = url
+ return render_media(ext, {'URL' : link })
+
+
+def fetch_urls(item, url_set):
+ if isinstance(item, forms.Form):
+ item = getattr(item, 'media', None)
+ if item is None:
+ return
+
+ if isinstance(item, forms.Media):
+ css, js = None, None
+ css = getattr(item, '_css', {})
+ js = getattr(item, '_js', [])
+ if css:
+ for key, list in css.items():
+ for url in list:
+ url_set[url] = key
+ if js:
+ for url in js:
+ url_set[url] = 1
+ elif isinstance(item, (str, unicode)):
+ url_set[item] = 1
+
+class MediaContainerNode(ContainerNode):
+
+ @consider_time
+ def render(self, context):
+ reqset = get_from_context_root(context, INSERT_TAG_KEY).get(self.name, None)
+ if not reqset:
+ return ''
+ items = reqset
+ items.sort()
+ url_set = SortedDict()
+ for obj in items:
+ fetch_urls(obj.item, url_set)
+ result = [media_tag(key) for key, value in url_set.items()]
+ if result:
+ return "\n".join(result)
+ return ''
+
+@register.tag
+def insert_handler(parser, token):
+ """
+ This is required tag for using insert_above tags. It must be
+ specified in the very "base" template and at the very beginning.
+
+ Simply, this tag controls the rendering of all tags after it. Note
+ that if any container node goes before this tag it won't be rendered
+ properly.
+
+ {% insert_handler %}
+ """
+ bits = token.split_contents()
+ if len(bits) != 1:
+ raise template.TemplateSyntaxError("'%s' takes no arguments" % bits[0])
+ nodelist = parser.parse()
+ if nodelist.get_nodes_by_type(InsertHandlerNode):
+ raise template.TemplateSyntaxError("'%s' cannot appear more than once in the same template" % bits[0])
+ return InsertHandlerNode(nodelist)
+
+@register.tag
+def container(parser, token):
+ """
+ This tag specifies some named block where items will be inserted
+ from all over the template.
+
+ {% container js %}
+
+ js - here is name of container
+
+ It's set while inserting string
+
+ {% insert_str js "<script src='js/jquery.js' type=...></script>" %}
+ """
+ bits = token.split_contents()
+ if len(bits) != 2:
+ raise template.TemplateSyntaxError("'%s' takes one argument" % bits[0])
+ return ContainerNode(bits[1])
+
+@register.tag
+def media_container(parser, token):
+ """
+ This tag is an example of how ContainerNode might be overriden.
+
+ {% media_container js %}
+
+ js - here is name of container
+
+ It's set while inserting string
+
+ {% insert_str js "js/jquery.js" %}
+ {% insert_str js "css/style.css" %}
+
+ Here only media urls are set. MediaContainerNode will identify
+ by last 3 characters and render on appropriate template.
+
+ By default only '.js' and 'css' files are rendered. It can be extended
+ by setting MEDIA_EXTENSION_FORMAT_MAP variable in settings.
+
+ """
+ bits = token.split_contents()
+ if len(bits) != 2:
+ raise template.TemplateSyntaxError("'%s' takes one argument" % bits[0])
+ return MediaContainerNode(bits[1])
+
+@register.tag
+def insert_str(parser, token):
+ """
+ This tag inserts specified string in containers.
+
+ Usage: {% insert_str container_name string_to_insert %}
+
+ Example: {% insert_str js "<script src="media/js/jquery.js"></script>" %}
+
+ """
+ bits = token.split_contents()
+ if len(bits) != 3:
+ raise template.TemplateSyntaxError("'%s' takes two arguments" % bits[0])
+ return InsertNode(bits[1], bits[2])
+
+@register.tag
+def insert_form(parser, token):
+ """
+ This tag inserts specified string in containers.
+
+ Usage: {% insert_str container_name form %}
+
+ Example: {% insert_form js form %}
+
+ """
+ bits = token.split_contents()
+ if len(bits) != 3:
+ raise template.TemplateSyntaxError("'%s' takes two arguments" % bits[0])
+ return InsertNode(bits[1], bits[2])
+
+
+@register.tag
+def insert(parser, token):
+ """
+ This tag with end token allows to insert not only one string.
+
+ {% insert js %}
+ <script>
+ $(document).ready(function(){
+ alert('hello, {{ user }}!');
+ });
+ </script>
+ {% endinsert %}
+ """
+ subnodes = parser.parse(('endinsert',))
+ parser.delete_first_token()
+ bits = token.contents.split()
+ if len(bits) < 2:
+ raise template.TemplateSyntaxError(u"'%r' tag requires 2 arguments." % bits[0])
+ return InsertNode(bits[1], subnodes = subnodes)
+
+register.filter('media_tag', media_tag)
MANAGERS = ADMINS
-## guess if we run on the 'prod' site (:) or on a working laptop
+####################
+# guess if we run on the 'prod' site (:) that for now uses /root/myslice and run manage.py
+# or on a working laptop, in which case we use ~/git/myslice-django
import os, os.path
ROOT=''
def init_root ():
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
+ # see details in devel/django-insert-above-1.0-4
+ 'insert_above',
'myslice',
+ 'auth',
+ 'slice',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
}
AUTHENTICATION_BACKENDS = ( 'auth.backend.MyCustomBackend', )
+
+#################### for insert_above
+#IA_JS_FORMAT = "<script type='text/javascript' src='{URL}' />"
+IA_MEDIA_PREFIX = '/code/'
# from django.contrib import admin
# admin.autodiscover()
-urlpatterns = patterns('',
+# to enable insert_above stuff
+from django.template.loader import add_to_builtins
+add_to_builtins('insert_above.templatetags.insert_tags')
+
+urlpatterns = patterns(
+ '',
# Examples:
# url(r'^$', 'myslice.views.home', name='home'),
# url(r'^myslice/', include('myslice.foo.urls')),
# Uncomment the next line to enable the admin:
# url(r'^admin/', include(admin.site.urls)),
(r'^login/$', 'auth.views.login_user'),
+ (r'^slice/$', 'slice.views.foo'),
)
--- /dev/null
+from django.db import models
+
+# Create your models here.
--- /dev/null
+{% insert_handler %}
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title>Foo - experimental page with foo= {{ foo }} </title>
+{% media_container media %}
+
+</head>
+
+<body>
+<h1>Again, foo = {{ foo }} </h1>
+<hr>
+{% block content %} and more stuff if needed {% endblock %}
+</body> </html>
--- /dev/null
+<ul>
+{% for k,v in menu_items.iteritems %}
+ <li> <a href="{{ v }}"> {{ k }} </a> </li>
+{% endfor %}
+</ul>
--- /dev/null
+{% extends 'foo-base.html' %}
+
+{% block content %}
+{% insert_str media "js/mathjax.js" %}
+{% insert_str media "css/mathjax.css" %}
+{{ content_string }}
+{% endblock %}
+
--- /dev/null
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
--- /dev/null
+# Create your views here.
+from django.core.context_processors import csrf
+from django.template import RequestContext
+from django.template.loader import render_to_string
+from django.shortcuts import render_to_response
+
+def foo (request):
+
+ content_string = render_to_string ('foo-menu.html',
+ {'menu_items' : {'item1':'/url1/', 'item2':'/url2',},
+ 'current_item': 'item1'})
+
+ result=render_to_response('foo.html',{'foo':'bar', 'content_string' : content_string },
+ context_instance=RequestContext(request))
+
+ print 'foo : result=',result
+
+ return result
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title> {{ title }} </title>
+{{
+</head>
+
+<body>
+<div class='wrapper'>
+
+ <div class='top'>
+ {% block top %}
+ <div class="header">
+ <a href="/" alt="Home"><img class="logo" src="{{ STATIC_URL }}myslice-logo.png" alt="MySlice" /></a>
+ </div>
+ {% endblock top %}
+ </div>
+ <div class='menubar'>
+ {% block menubar %}
+ <h1> Empty menubar for now </h1>
+ {% endblock menubar %}
+ </div>
+ <div class='centered content'>
+ {% block content %}
+ Welcome...
+ {% endblock content %}
+ </div>
+</div>
+</body> </html>