Commit bf9a46ea by Timothée Peignier

add mhtml variant

parent 27a51434
...@@ -7,7 +7,7 @@ Backwards Incompatible Changes ...@@ -7,7 +7,7 @@ Backwards Incompatible Changes
A list of backwards incompatible changes A list of backwards incompatible changes
Version 1.1.0 Version 1.1.0
=========== =============
* Most of the settings name have change to be prefixed by ``PIPELINE_``. * Most of the settings name have change to be prefixed by ``PIPELINE_``.
* CSSTidy isn't the default anymore, YUI Compressor is now the default. * CSSTidy isn't the default anymore, YUI Compressor is now the default.
......
...@@ -72,9 +72,9 @@ Group options ...@@ -72,9 +72,9 @@ Group options
**Optional** **Optional**
Is the variant you want to apply to your CSS. This allow you to embed images and Is the variant you want to apply to your CSS. This allow you to embed images
fonts in CSS with data-URI. and fonts in CSS with data-URI or MHTML.
Allowed values are : ``None`` or ``datauri``. Allowed values are : ``None``, ``datauri`` or ``mhtml``.
Defaults to ``None``. Defaults to ``None``.
......
...@@ -14,6 +14,10 @@ EMBEDDABLE = r'[\A\/]embed\/' ...@@ -14,6 +14,10 @@ EMBEDDABLE = r'[\A\/]embed\/'
URL_DETECTOR = r'url\([\'"]?([^\s)]+\.[a-z]+)[\'"]?\)' URL_DETECTOR = r'url\([\'"]?([^\s)]+\.[a-z]+)[\'"]?\)'
URL_REPLACER = r'url\(__EMBED__(.+?)(\?\d+)?\)' URL_REPLACER = r'url\(__EMBED__(.+?)(\?\d+)?\)'
MHTML_START = "/*\r\nContent-Type: multipart/related; boundary=\"MHTML_MARK\"\r\n\r\n"
MHTML_SEPARATOR = "--MHTML_MARK\r\n"
MHTML_END = "\r\n--MHTML_MARK--\r\n*/\r\n"
MIME_TYPES = { MIME_TYPES = {
'.png': 'image/png', '.png': 'image/png',
'.jpg': 'image/jpeg', '.jpg': 'image/jpeg',
...@@ -43,7 +47,7 @@ class Compressor(object): ...@@ -43,7 +47,7 @@ class Compressor(object):
return to_class(settings.PIPELINE_CSS_COMPRESSOR) return to_class(settings.PIPELINE_CSS_COMPRESSOR)
css_compressor = property(css_compressor) css_compressor = property(css_compressor)
def compress_js(self, paths, templates=None): def compress_js(self, paths, templates=None, asset_url=None):
"""Concatenate and compress JS files""" """Concatenate and compress JS files"""
js = self.concatenate(paths) js = self.concatenate(paths)
if templates: if templates:
...@@ -51,7 +55,7 @@ class Compressor(object): ...@@ -51,7 +55,7 @@ class Compressor(object):
js = getattr(self.js_compressor(verbose=self.verbose), 'compress_js')(js) js = getattr(self.js_compressor(verbose=self.verbose), 'compress_js')(js)
return js return js
def compress_css(self, paths, variant=None): def compress_css(self, paths, variant=None, asset_url=None):
"""Concatenate and compress CSS files""" """Concatenate and compress CSS files"""
css = self.concatenate_and_rewrite(paths, variant) css = self.concatenate_and_rewrite(paths, variant)
css = getattr(self.css_compressor(verbose=self.verbose), 'compress_css')(css) css = getattr(self.css_compressor(verbose=self.verbose), 'compress_css')(css)
...@@ -59,6 +63,8 @@ class Compressor(object): ...@@ -59,6 +63,8 @@ class Compressor(object):
return css return css
elif variant == "datauri": elif variant == "datauri":
return self.with_data_uri(css) return self.with_data_uri(css)
elif variant == "mhtml":
return self.with_mhtml(css, asset_url)
else: else:
raise CompressorError("\"%s\" is not a valid variant" % variant) raise CompressorError("\"%s\" is not a valid variant" % variant)
...@@ -158,6 +164,29 @@ class Compressor(object): ...@@ -158,6 +164,29 @@ class Compressor(object):
return "url(\"data:%s;charset=utf-8;base64,%s\")" % (mime_type, data) return "url(\"data:%s;charset=utf-8;base64,%s\")" % (mime_type, data)
return re.sub(URL_REPLACER, datauri, css) return re.sub(URL_REPLACER, datauri, css)
def with_mhtml(self, css, asset_url):
paths = {}
def mhtml(match):
path = match.group(1)
if not path in paths:
paths[path] = "%s-%s" % (match.start(), os.path.basename(path))
return "url(mhtml:%s!%s)" % (asset_url, paths[path])
css = re.sub(URL_REPLACER, mhtml, css)
mhtml = []
for path, location in paths.items():
mime_type = self.mime_type(path)
data = self.encoded_content(path)
mhtml.extend([
MHTML_SEPARATOR,
"Content-Location: %s\r\n" % location,
"Content-Type: %s\r\n" % mime_type,
"Content-Transfer-Encoding: base64\r\n\r\n",
data,
"\r\n"
])
output = [MHTML_START, mhtml, MHTML_END, css]
return ''.join([part for parts in output for part in parts])
def encoded_content(self, path): def encoded_content(self, path):
if path in self.__class__.asset_contents: if path in self.__class__.asset_contents:
return self.__class__.asset_contents[path] return self.__class__.asset_contents[path]
......
...@@ -56,7 +56,8 @@ class Packager(object): ...@@ -56,7 +56,8 @@ class Packager(object):
print "Version: %s" % version print "Version: %s" % version
print "Saving: %s" % self.compressor.relative_path(output_filename) print "Saving: %s" % self.compressor.relative_path(output_filename)
paths = self.compile(package['paths']) paths = self.compile(package['paths'])
content = compress(paths, **kwargs) content = compress(paths,
asset_url=self.individual_url(output_filename), **kwargs)
self.save_file(output_filename, content) self.save_file(output_filename, content)
signal.send(sender=self, package=package, version=version) signal.send(sender=self, package=package, version=version)
else: else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment