Closed ustun closed 10 years ago
Here is a bit improved one, since we don't need the closing tags now:
class AssetsNode(template.Node):
# For testing, to inject a mock bundle
BundleClass = Bundle
def __init__(self, filters, output, debug, files, childnodes=None):
self.childnodes = childnodes
self.output = output
self.files = files
self.filters = filters
self.debug = debug
def resolve(self, context={}):
"""We allow variables to be used for all arguments; this function
resolves all data against a given context;
This is a separate method as the management command must have
the ability to check if the tag can be resolved without a context.
"""
def resolve_var(x):
if x is None:
return None
else:
try:
return template.Variable(x).resolve(context)
except template.VariableDoesNotExist, e:
# Django seems to hide those; we don't want to expose
# them either, I guess.
raise
def resolve_bundle(name):
# If a bundle with that name exists, use it. Otherwise,
# assume a filename is meant.
try:
return get_env()[name]
except KeyError:
return name
return self.BundleClass(
*[resolve_bundle(resolve_var(f)) for f in self.files],
**{'output': resolve_var(self.output),
'filters': resolve_var(self.filters),
'debug': parse_debug_value(resolve_var(self.debug))})
def render(self, context):
bundle = self.resolve(context)
result = u""
for url in bundle.urls(env=get_env()):
context.update({'ASSET_URL': url})
try:
result += self.childnodes.render(context)
finally:
context.pop()
return result
class JsCssAssetsNode(AssetsNode):
def render(self, context):
bundle = self.resolve(context)
result = u""
for url in bundle.urls(env=get_env()):
result += self.template.format(ASSET_URL=url)
return result
class JsAssetsNode(JsCssAssetsNode):
template = '<script type="text/javascript" src="{ASSET_URL}"></script>'
class CssAssetsNode(JsCssAssetsNode):
template = '<link rel="stylesheet" type="text/css" href="{ASSET_URL}" media="all" />'
def assets(parser, token, type=""):
filters = None
output = None
debug = None
files = []
# parse the arguments
args = token.split_contents()[1:]
for arg in args:
# Handle separating comma; for backwards-compatibility
# reasons, this is currently optional, but is enforced by
# the Jinja extension already.
if arg[-1] == ',':
arg = arg[:-1]
if not arg:
continue
# determine if keyword or positional argument
arg = arg.split('=', 1)
if len(arg) == 1:
name = None
value = arg[0]
else:
name, value = arg
# handle known keyword arguments
if name == 'output':
output = value
elif name == 'debug':
debug = value
elif name == 'filters':
filters = value
elif name == 'filter':
filters = value
warnings.warn('The "filter" option of the {% assets %} '
'template tag has been renamed to '
'"filters" for consistency reasons.',
ImminentDeprecationWarning)
# positional arguments are source files
elif name is None:
files.append(value)
else:
raise template.TemplateSyntaxError('Unsupported keyword argument "%s"'%name)
if type == "":
# capture until closing tag
childnodes = parser.parse(("endassets" + type,))
parser.delete_first_token()
return AssetsNode(filters, output, debug, files, childnodes)
elif type == "js":
return JsAssetsNode(filters, output, debug, files)
elif type == "css":
return CssAssetsNode(filters, output, debug, files)
# If Coffin is installed, expose the Jinja2 extension
try:
from coffin.template import Library as CoffinLibrary
except ImportError:
register = template.Library()
else:
register = CoffinLibrary()
from webassets.ext.jinja2 import AssetsExtension
from django_assets.env import get_env
register.tag(AssetsExtension, environment={'assets_environment': get_env()})
# expose the default Django tag
register.tag('assets', assets)
register.tag('assetsjs', functools.partial(assets, type='js'))
register.tag('assetscss', functools.partial(assets, type='css'))
Instead of
it would be better if we could just do
It could even detect that it is a js file, so we wouldn't have to have different asset tags like assetscss etc.
Here is a simple implementation that could be improved: