diff --git a/compressor/contrib/jinja2ext.py b/compressor/contrib/jinja2ext.py index 6ff6760..73af200 100644 --- a/compressor/contrib/jinja2ext.py +++ b/compressor/contrib/jinja2ext.py @@ -1,27 +1,14 @@ -from django.core.exceptions import ImproperlyConfigured - from jinja2 import nodes from jinja2.ext import Extension from jinja2.exceptions import TemplateSyntaxError -from compressor.conf import settings -from compressor.utils import get_class -from compressor.templatetags.compress import OUTPUT_FILE -from compressor.cache import (cache_get, cache_set, - get_templatetag_cachekey) +from compressor.templatetags.compress import OUTPUT_FILE, CompressorMixin -class CompressorExtension(Extension): +class CompressorExtension(CompressorMixin, Extension): tags = set(['compress']) - @property - def compressors(self): - return { - 'js': settings.COMPRESS_JS_COMPRESSOR, - 'css': settings.COMPRESS_CSS_COMPRESSOR, - } - def parse(self, parser): lineno = parser.stream.next().lineno kindarg = parser.parse_expression() @@ -46,40 +33,16 @@ class CompressorExtension(Extension): body).set_lineno(lineno) def _compress(self, kind, mode, caller): - mode = mode or OUTPUT_FILE - Compressor = get_class(self.compressors.get(kind), - exception=ImproperlyConfigured) - original_content = caller() - compressor = Compressor(original_content) # This extension assumes that we won't force compression forced = False - - # Prepare the actual compressor and check cache - cache_key, cache_content = self.render_cached(kind, mode, compressor, - forced) - if cache_content is not None: - return cache_content - - # call compressor output method and handle exceptions - try: - rendered_output = compressor.output(mode, forced) - if cache_key: - cache_set(cache_key, rendered_output) - return rendered_output - except Exception, e: - if settings.DEBUG: - raise e - - # Or don't do anything in production - return original_content - - def render_cached(self, kind, mode, compressor, forced): - """ - If enabled checks the cache for the given compressor's cache key - and return a tuple of cache key and output - """ - if settings.COMPRESS_ENABLED and not forced: - cache_key = get_templatetag_cachekey(compressor, mode, kind) - cache_content = cache_get(cache_key) - return cache_key, cache_content - return None, None + + mode = mode or OUTPUT_FILE + original_content = caller() + context = { + 'original_content': original_content + } + return self.render_compressed(context, kind, mode, forced=forced) + + def get_original_content(self, context): + return context['original_content'] + \ No newline at end of file diff --git a/compressor/templatetags/compress.py b/compressor/templatetags/compress.py index f1b1f01..c35140b 100644 --- a/compressor/templatetags/compress.py +++ b/compressor/templatetags/compress.py @@ -14,41 +14,39 @@ OUTPUT_INLINE = 'inline' OUTPUT_MODES = (OUTPUT_FILE, OUTPUT_INLINE) -class CompressorNode(template.Node): - - def __init__(self, nodelist, kind=None, mode=OUTPUT_FILE, name=None): - self.nodelist = nodelist - self.kind = kind - self.mode = mode - self.name = name - - def compressor_cls(self, *args, **kwargs): - compressors = { - "css": settings.COMPRESS_CSS_COMPRESSOR, - "js": settings.COMPRESS_JS_COMPRESSOR, +class CompressorMixin(object): + + def get_original_content(self, context): + raise NotImplementedError + + @property + def compressors(self): + return { + 'js': settings.COMPRESS_JS_COMPRESSOR, + 'css': settings.COMPRESS_CSS_COMPRESSOR, } - if self.kind not in compressors.keys(): + + def compressor_cls(self, kind, *args, **kwargs): + if kind not in self.compressors.keys(): raise template.TemplateSyntaxError( "The compress tag's argument must be 'js' or 'css'.") - return get_class(compressors.get(self.kind), - exception=ImproperlyConfigured)(*args, **kwargs) + + return get_class(self.compressors.get(kind), + exception=ImproperlyConfigured)(*args, **kwargs) + + def get_compressor(self, context, kind): + return self.compressor_cls(kind, + content=self.get_original_content(context), + context=context) - def debug_mode(self, context): - if settings.COMPRESS_DEBUG_TOGGLE: - # Only check for the debug parameter - # if a RequestContext was used - request = context.get('request', None) - if request is not None: - return settings.COMPRESS_DEBUG_TOGGLE in request.GET - - def render_offline(self, context, forced): + def render_offline(self, context, forced=False): """ If enabled and in offline mode, and not forced or in debug mode check the offline cache and return the result if given """ if (settings.COMPRESS_ENABLED and settings.COMPRESS_OFFLINE) and not forced: - key = get_offline_hexdigest(self.nodelist.render(context)) + key = get_offline_hexdigest(self.get_original_content(context)) offline_manifest = get_offline_manifest() if key in offline_manifest: return offline_manifest[key] @@ -57,47 +55,76 @@ class CompressorNode(template.Node): 'enabled but key "%s" is missing from offline manifest. ' 'You may need to run "python manage.py compress".' % key) - def render_cached(self, compressor, forced): + def render_cached(self, compressor, kind, mode, forced=False): """ If enabled checks the cache for the given compressor's cache key and return a tuple of cache key and output """ if settings.COMPRESS_ENABLED and not forced: - cache_key = get_templatetag_cachekey( - compressor, self.mode, self.kind) + cache_key = get_templatetag_cachekey(compressor, mode, kind) cache_content = cache_get(cache_key) return cache_key, cache_content return None, None + + def render_compressed(self, context, kind, mode, forced=False): + + # See if it has been rendered offline + cached_offline = self.render_offline(context, forced=forced) + if cached_offline: + return cached_offline + + context['compressed'] = {'name': getattr(self, 'name', None)} + compressor = self.get_compressor(context, kind) + + # Prepare the actual compressor and check cache + cache_key, cache_content = self.render_cached(compressor, kind, mode, forced=forced) + if cache_content is not None: + return cache_content - def render_output(self, compressor, forced=False): - return compressor.output(self.mode, forced=forced) + # call compressor output method and handle exceptions + try: + rendered_output = self.render_output(compressor, mode, forced=forced) + if cache_key: + cache_set(cache_key, rendered_output) + return rendered_output + except Exception, e: + if settings.DEBUG: + raise e + + # Or don't do anything in production + return self.get_original_content(context) + + def render_output(self, compressor, mode, forced=False): + return compressor.output(mode, forced=forced) + + +class CompressorNode(CompressorMixin, template.Node): + + def __init__(self, nodelist, kind=None, mode=OUTPUT_FILE, name=None): + self.nodelist = nodelist + self.kind = kind + self.mode = mode + self.name = name + + def get_original_content(self, context): + return self.nodelist.render(context) + + def debug_mode(self, context): + if settings.COMPRESS_DEBUG_TOGGLE: + # Only check for the debug parameter + # if a RequestContext was used + request = context.get('request', None) + if request is not None: + return settings.COMPRESS_DEBUG_TOGGLE in request.GET def render(self, context, forced=False): # Check if in debug mode if self.debug_mode(context): - return self.nodelist.render(context) - - # See if it has been rendered offline - cached_offline = self.render_offline(context, forced) - if cached_offline: - return cached_offline - - # Prepare the compressor - context['compressed'] = {'name': self.name} - compressor = self.compressor_cls(content=self.nodelist.render(context), - context=context) - # Check cache - cache_key, cache_content = self.render_cached(compressor, forced) - if cache_content is not None: - return cache_content - - # call compressor output method and handle exceptions - rendered_output = self.render_output(compressor, forced) - if cache_key: - cache_set(cache_key, rendered_output) - return rendered_output - + return self.get_original_content(context) + + return self.render_compressed(context, self.kind, self.mode, forced=forced) + @register.tag def compress(parser, token):