From 65d84452c2b58dd76f97e4c28e5ec401aff890c4 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Wed, 21 Nov 2012 13:47:19 +0100 Subject: [PATCH] insert_above is integrated for adding js/css on the fly a dummy 'slice' app for playing with the rendering engine --- Makefile | 5 + {templates => auth/templates}/auth.html | 0 devel/django-insert-above-1.0.4/PKG-INFO | 235 ++++++++++++++ devel/django-insert-above-1.0.4/README | 218 +++++++++++++ devel/django-insert-above-1.0.4/setup.py | 26 ++ devel/django-install.txt | 6 + insert_above/__init__.py | 0 insert_above/templatetags/__init__.py | 0 insert_above/templatetags/insert_tags.py | 395 +++++++++++++++++++++++ myslice/settings.py | 12 +- myslice/urls.py | 8 +- slice/__init__.py | 0 slice/models.py | 3 + slice/templates/foo-base.html | 13 + slice/templates/foo-menu.html | 5 + slice/templates/foo.html | 8 + slice/tests.py | 16 + slice/views.py | 18 ++ templates/myslice.html | 28 ++ 19 files changed, 994 insertions(+), 2 deletions(-) rename {templates => auth/templates}/auth.html (100%) create mode 100644 devel/django-insert-above-1.0.4/PKG-INFO create mode 100644 devel/django-insert-above-1.0.4/README create mode 100644 devel/django-insert-above-1.0.4/setup.py create mode 100644 insert_above/__init__.py create mode 100644 insert_above/templatetags/__init__.py create mode 100644 insert_above/templatetags/insert_tags.py create mode 100644 slice/__init__.py create mode 100644 slice/models.py create mode 100644 slice/templates/foo-base.html create mode 100644 slice/templates/foo-menu.html create mode 100644 slice/templates/foo.html create mode 100644 slice/tests.py create mode 100644 slice/views.py create mode 100644 templates/myslice.html diff --git a/Makefile b/Makefile index d4fd1302..99fb3210 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,7 @@ +# 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 diff --git a/templates/auth.html b/auth/templates/auth.html similarity index 100% rename from templates/auth.html rename to auth/templates/auth.html diff --git a/devel/django-insert-above-1.0.4/PKG-INFO b/devel/django-insert-above-1.0.4/PKG-INFO new file mode 100644 index 00000000..b3686a68 --- /dev/null +++ b/devel/django-insert-above-1.0.4/PKG-INFO @@ -0,0 +1,235 @@ +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 `` + + 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 `` + 5. `IA_CSS_FORMAT`, by default `` + 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 %} + + + + {% media_container media %} + + $(document).ready(function(){ + {% container ready %} + }); + + + + {% block content %} + {% endblock %} + + + ~~~~ + + 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 %} + + ~~~~ + + 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 %} +
+ {% 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} + + + + + + + + $(document).ready(function(){ + $('ul.menu').each(function(){ + $(this).superanimation(); + }); + }); + + + + Hello + + World +
+ + + ~~~~ + + What shall be noted? + ------------------- + + 1. `js/mathjax.js` automatically becomes `` + and `css/animated.menu.css` becomes `` + 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 diff --git a/devel/django-insert-above-1.0.4/README b/devel/django-insert-above-1.0.4/README new file mode 100644 index 00000000..0aaa62da --- /dev/null +++ b/devel/django-insert-above-1.0.4/README @@ -0,0 +1,218 @@ +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 `` + +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 `` +5. `IA_CSS_FORMAT`, by default `` +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 %} + + + +{% media_container media %} + +$(document).ready(function(){ +{% container ready %} +}); + + + +{% block content %} +{% endblock %} + + +~~~~ + +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 %} + +~~~~ + +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 %} +
+{% 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} + + + + + + + +$(document).ready(function(){ + $('ul.menu').each(function(){ + $(this).superanimation(); + }); +}); + + + +Hello + +World +
+ + +~~~~ + +What shall be noted? +------------------- + +1. `js/mathjax.js` automatically becomes `` +and `css/animated.menu.css` becomes `` +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 + diff --git a/devel/django-insert-above-1.0.4/setup.py b/devel/django-insert-above-1.0.4/setup.py new file mode 100644 index 00000000..9517c678 --- /dev/null +++ b/devel/django-insert-above-1.0.4/setup.py @@ -0,0 +1,26 @@ +#!/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", + ], +) diff --git a/devel/django-install.txt b/devel/django-install.txt index 3bb153ff..72e83d24 100644 --- a/devel/django-install.txt +++ b/devel/django-install.txt @@ -42,3 +42,9 @@ and I was getting a lot of warnings relating to that anyways ==================== 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 + +======================================== diff --git a/insert_above/__init__.py b/insert_above/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/insert_above/templatetags/__init__.py b/insert_above/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/insert_above/templatetags/insert_tags.py b/insert_above/templatetags/insert_tags.py new file mode 100644 index 00000000..475faa16 --- /dev/null +++ b/insert_above/templatetags/insert_tags.py @@ -0,0 +1,395 @@ +""" +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', "") +CSS_FORMAT = getattr(settings, 'IA_CSS_FORMAT', "") + +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 '' + + 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 "" % (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 "" % (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 + + 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 "" %} + """ + 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 "" %} + + """ + 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 %} + + {% 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) diff --git a/myslice/settings.py b/myslice/settings.py index 6c9d949c..31432e5c 100644 --- a/myslice/settings.py +++ b/myslice/settings.py @@ -9,7 +9,9 @@ ADMINS = ( 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 (): @@ -127,7 +129,11 @@ INSTALLED_APPS = ( '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: @@ -164,3 +170,7 @@ LOGGING = { } AUTHENTICATION_BACKENDS = ( 'auth.backend.MyCustomBackend', ) + +#################### for insert_above +#IA_JS_FORMAT = "