import re from django.conf import settings DEFAULT_JS_TAG = '' DEFAULT_CSS_TAG = '' 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', '') 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 '' % 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 '' % 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( '', content) return response