Login

head inclusion middleware

Author:
bowdengm
Posted:
February 15, 2009
Language:
Python
Version:
1.0
Score:
1 (after 1 ratings)

Inspired by http://www.djangosnippets.org/snippets/712/

This loads in css and javascript files where you want them (usually in the head) - but allows you to put them anywhere in your code - i.e. in a TemplateTag.

so your head code will look like this:

<head> ... <!-- HEAD_init --> ... </head>

then somewhere in your templates you can load in javascript or css files like so:

<!-- HEAD_include myfile.js myotherfile.css -->

It automatically checks if you've already included the files, and only puts them in once. It automatically figures out if its a javascript or css file by the file name - If you have an irregular filename (i.e. a google maps api script url) you can force it by using either of the following tags:

<!-- HEAD_include_js [my javascript file] --> <!-- HEAD_include_css [my css file] -->

Or you can write inline code to get rendered in the head:

<!-- HEAD_render <script> someJavascriptCall(); </script> -->

Todo: make it compress the js into one file...

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
import re

from django.conf import settings


DEFAULT_JS_TAG = '<script type="text/javascript" src="%s"></script>'
DEFAULT_CSS_TAG = '<link rel="stylesheet" type="text/css" href="%s" />'
DEFAULT_JS_DIR = 'js'
DEFAULT_CSS_DIR = 'css'

HEAD_BASE = getattr(settings, 'HEAD_INCLUDE_BASE', settings.MEDIA_URL)
PREFIX_RE = getattr(settings, 'HEAD_INCLUDE_PREFIX_RE', '<!-- *HEAD_')
SUFFIX_RE = getattr(settings, 'HEAD_INCLUDE_SUFFIX_RE', ' *-->')
TAGS = {'js': getattr(settings, 'HEAD_INCLUDE_JS_TAG', DEFAULT_JS_TAG),
		'css': getattr(settings, 'HEAD_INCLUDE_CSS_TAG', DEFAULT_CSS_TAG)}
PATHS = {'js':'js/', 'css':'css/'}

HEAD_RE = re.compile(
	r'%s(include|version|include_js|include_css|render) +([\s\S]*?)%s' % (PREFIX_RE, SUFFIX_RE))
HEAD_INIT_RE = re.compile(
	'%sinit%s' % (PREFIX_RE, SUFFIX_RE))

class HeadLoader:

	def __init__(self):
		self._components = []
		self._js_components = []
		self._css_components = []

	def add_component(self, new_component_name, component_type = ''):
		if component_type == 'js' and not new_component_name in self._js_components:
			self._js_components.append(new_component_name)
		elif component_type == 'css' and not new_component_name in self._css_components:
			self._css_components.append(new_component_name)
		elif component_type == '' and not new_component_name in self._components:
			self._components.append(new_component_name)

	def render(self):
		#self._components.reverse()
		head = ''
		head += '\n' + '\n'.join(self._render_component(component, 'css') for component in self._css_components)
		head += '\n' + '\n'.join(self._render_component(component, 'js') for component in self._js_components)
		head += '\n' + '\n'.join(self._render_component(component) for component in self._components)
		
		return head
		

	def _has_component(self, component_name):
		return component_name in self._components

	def _render_component(self, component_name, component_type = ''):
		
		if component_type == '':
			# check what sort of component this is - based on the file name either ending with .js or .css
			last_three = component_name[-3:]
			if last_three == '.js':
				component_type = 'js'
			elif last_three == 'css':
				component_type = 'css'
			else:
				# we don't know what to do with anything else!
				return '<!-- HEAD - unknown compoent type : %s -->' % component_name
			
		# check if we've got an absolute or external js or css file
		if component_name[:7] == 'http://' or component_name[:1] == '/': 
			return TAGS[component_type] % (component_name,)
		else:
			return TAGS[component_type] % (HEAD_BASE + PATHS[component_type] + component_name,)


class HeadIncludeMiddleware(object):
	def process_response(self, request, response):
		components = []
		js_components = []
		css_components = []
		extra_head = []
		node = HeadLoader()
		def collect(match):
			cmd, data = match.groups()
			if cmd == 'include':
				components.extend(data.split())
			elif cmd == 'include_js':
				js_components.extend(data.split())
			elif cmd == 'include_css':
				css_components.extend(data.split())
			elif cmd == 'render':
				extra_head.append(data)
			else:
				return '<!-- UNKNOWN COMMAND HEAD_%s -->' % cmd
			return ''
		
		content = HEAD_RE.sub(collect, response.content)
		
		for component in components:
			node.add_component(component)
		
		for component in js_components:
			node.add_component(component, 'js')
			
		for component in css_components:
			node.add_component(component, 'css')
	
			
		rendered = node.render() + '\n'.join(extra_head)
		content = HEAD_INIT_RE.sub(rendered, content, 1)
		response.content = HEAD_INIT_RE.sub(
			'<!-- WARNING: MULTIPLE HEAD_init STATEMENTS -->', content)
			
		return response
		

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

akaihola (on March 11, 2009):

Markup for the YUI snippet link seems to be reversed.

#

Please login first before commenting.