Merge pull request #144 from oasiswork/jd-capitalize-margin-float

Add an option to capitalize margin and float properties
This commit is contained in:
Peter Bengtsson 2016-03-15 15:35:09 -04:00
commit dcab22bd74
5 changed files with 93 additions and 6 deletions

View File

@ -64,6 +64,12 @@ def main(args):
action="store_true", dest="remove_classes"
)
parser.add_argument(
"--capitalize-float-margin", default=False,
help="Capitalize float and margin properties for outlook.com compat.",
action="store_true", dest="capitalize_float_margin"
)
parser.add_argument(
"--strip-important", default=False,
help="Remove '!important' for all css declarations.",

View File

@ -81,8 +81,27 @@ def _cache_parse_css_string(css_body, validate=True):
"""
return cssutils.parseString(css_body, validate=validate)
def capitalize_float_margin(css_body):
"""Capitalize float and margin CSS property names
"""
def _capitalize_property(match):
return '{0}:{1}{2}'.format(
match.group('property').capitalize(),
match.group('value'),
match.group('terminator'))
return _lowercase_margin_float_rule.sub(_capitalize_property, css_body)
_element_selector_regex = re.compile(r'(^|\s)\w')
_cdata_regex = re.compile(r'\<\!\[CDATA\[(.*?)\]\]\>', re.DOTALL)
_lowercase_margin_float_rule = re.compile(
r'''(?P<property>margin(-(top|bottom|left|right))?|float)
:
(?P<value>.*?)
(?P<terminator>$|;)''',
re.IGNORECASE | re.VERBOSE)
_importants = re.compile('\s*!important')
#: The short (3-digit) color codes that cause issues for IBM Notes
_short_color_codes = re.compile(r'^#([0-9a-f])([0-9a-f])([0-9a-f])$', re.I)
@ -103,6 +122,7 @@ class Premailer(object):
keep_style_tags=False,
include_star_selectors=False,
remove_classes=True,
capitalize_float_margin=False,
strip_important=True,
external_styles=None,
css_text=None,
@ -125,6 +145,7 @@ class Premailer(object):
# this will always preserve the original css
self.keep_style_tags = keep_style_tags
self.remove_classes = remove_classes
self.capitalize_float_margin = capitalize_float_margin
# whether to process or ignore selectors like '* { foo:bar; }'
self.include_star_selectors = include_star_selectors
if isinstance(external_styles, STR_TYPE):
@ -419,6 +440,14 @@ class Premailer(object):
parent = item.getparent()
del parent.attrib['class']
# Capitalize Margin properties
# To fix weird outlook bug
# https://www.emailonacid.com/blog/article/email-development/outlook.com-does-support-margins
if self.capitalize_float_margin:
for item in page.xpath('//@style'):
mangled = capitalize_float_margin(item)
item.getparent().attrib['style'] = mangled
# Add align attributes to images if they have a CSS float value of
# right or left. Outlook (both on desktop and on the web) are bad at
# understanding floats, but they do understand the HTML align attrib.

View File

@ -16,9 +16,3 @@ class TestMergeStyle(unittest.TestCase):
# Invalid syntax does not raise
inline = '{color:pink} :hover{color:purple} :active{color:red}'
merge_styles(inline, [], [])
def test_important_rule(self):
# No exception after #133
csstext = 'font-size:1px !important'
parsed_csstext = csstext_to_pairs(csstext)
self.assertEqual(('font-size', '1px'), parsed_csstext[0])

View File

@ -806,6 +806,45 @@ ical-align:middle" bgcolor="red" valign="middle">Cell 2</td>
compare_html(expect_html, result_html)
def test_uppercase_margin(self):
"""Option to comply with outlook.com
https://emailonacid.com/blog/article/email-development/outlook.com-does-support-margins
"""
html = """<html>
<head>
<title>Title</title>
</head>
<style>
h1 {margin: 0}
h2 {margin-top:0;margin-bottom:0;margin-left:0;margin-right:0}
</style>
<body>
<h1>a</h1>
<h2>
b
</h2>
</body>
</html>"""
expect_html = """<html>
<head>
<title>Title</title>
</head>
<body>
<h1 style="Margin:0">a</h1>
<h2 style="Margin-bottom:0; Margin-left:0; Margin-right:0; Margin-top:0">
b
</h2>
</body>
</html>"""
p = Premailer(html, capitalize_float_margin=True)
result_html = p.transform()
compare_html(expect_html, result_html)
def test_strip_important(self):
"""Get rid of !important. Makes no sense inline."""
html = """<html>

View File

@ -0,0 +1,19 @@
import unittest
from premailer.premailer import capitalize_float_margin
class UtilsTestCase(unittest.TestCase):
def testcapitalize_float_margin(self):
self.assertEqual(
capitalize_float_margin('margin:1em'),
'Margin:1em')
self.assertEqual(
capitalize_float_margin('margin-left:1em'),
'Margin-left:1em')
self.assertEqual(
capitalize_float_margin('float:right;'),
'Float:right;')
self.assertEqual(
capitalize_float_margin('float:right;color:red;margin:0'),
'Float:right;color:red;Margin:0')