import os, re from os import path from django.template import Library, Node, TemplateSyntaxError from django.conf import settings register = Library() class JSPacker: """ JS compressor. This commpress a javascript content This class code is adapted from http://plone.org/products/resourceregistries """ def __init__(self): # protect this strings: # match a single quote # match anything but the single quote, a backslash and a newline "[^'\\\n]" # or match a null escape (\0 not followed by another digit) "\\0(?![0-9])" # or match a character escape (no newline) "\\[^\n]" self.patterns = [] self.protect(r"""('(?:[^'\\\n]|\\0(?![0-9])|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}|\\[^\n])*?'|""" r""""(?:[^"\\\n]|\\0(?![0-9])|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}|\\[^\n])*?")""") # protect regular expressions self.protect(r"""\s+(\/[^\/\n\r\*](?:\\/|[^\n\r])*\/g?i?)""") self.protect(r"""([^\w\$\/'"*)\?:]\/[^\/\n\r\*](?:\\/|[^\n\r])*\/g?i?)""") # protect IE conditional compilation self.protect(r'(/\*@.*?(?:\*/|\n|\*/(?!\n)))', re.DOTALL) # remove multiline comments self.sub(r'/\*.*?\*/', '', re.DOTALL) # strip whitespace at the beginning and end of each line self.sub(r'^[ \t\r\f\v]*(.*?)[ \t\r\f\v]*$', r'\1', re.MULTILINE) # after an equal sign a function definition is ok self.sub(r'=\s+(?=function)', r'=') # whitespace before some special chars self.sub(r'\s+([={},&|\?:\.()<>%!/\]])', r'\1') # whitespace before plus chars if no other plus char before i self.sub(r'(? last_mtime def merge_js(self, jsname, jspath, fd): """ do merging and compressing of javascript """ global jspacker jsfile = open(jspath) jscontent = jsfile.read() jscontent = jspacker.pack(jscontent) fd.write('/* -- %s -- */\n\n%s\n\n\n' % (jsname, jscontent)) def js_tag(self): """ write js tag for merged file inclusion """ js_url = '%s%s' % (settings.MEDIA_URL, self.js_name) return '' % js_url def do_jsmerge(parser, token): """ This will merge javascript files in only one compressed javascript. Usage:: {% load jsmerge %} {% jsmerge jsname [jsfile1] [jsfile2] .. %} Example:: {% load jsmerge %} {% jsmerge jsmergefile js/file1.js js/file2.js js/file3.js %} This will create (if not exists) a /media/jsmergefile.js with three files merged. The HTML output for this will be:: """ tokens = token.contents.split() if len(tokens) < 2: raise TemplateSyntaxError(u"'%r' tag requires at least 1 arguments." % tokens[0]) js_name = tokens[1] return JSMergeNode(js_name, tokens[2:]) register.tag('jsmerge', do_jsmerge)