# -*- coding: utf-8 -*-
############################################################################
#
# Copyright © 2015 OnlineGroups.net and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
############################################################################
from __future__ import absolute_import, unicode_literals, print_function
from operator import attrgetter
from xml.sax.saxutils import escape
from zope.cachedescriptors.property import Lazy
from .matcher import (boldMatcher, emailMatcher, wwwMatcher, uriMatcher, )
from .splitmessage import split_message
[docs]class HTMLBody(object):
'''The HTML form of a plain-text email body.
:param str originalText: The original (plain) text'''
HTML_ESCAPE_TABLE = {
'"': """,
"'": "'"
}
def __init__(self, originalText):
if not originalText:
raise(ValueError('"originalText" argument required'))
self.originalText = originalText
self.matchers = [boldMatcher, emailMatcher, wwwMatcher, uriMatcher]
sorted(self.matchers, key=attrgetter('weight'))
[docs] def __iter__(self):
'''The marked-up lines in the main body'''
mainBody = self.splitBody[0]
lines = mainBody.rstrip().split('\n')
for line in lines:
retval = self.markup(line)
yield retval
[docs] def __unicode__(self):
'''The main part of the HTML body, as a Unicode string'''
retval = '\n'.join(self)
return retval
[docs] def __str__(self):
'''The main part of the HTML body, as an ASCII string. Non-ASCII characters are replaced
with XML entities.'''
retval = unicode(self).encode('ascii', 'xmlcharrefreplace')
return retval
@Lazy
def splitBody(self):
'''The body as a 2-tuple: main body, and remainder'''
retval = split_message(self.originalText)
return retval
[docs] def markup(self, line):
'''Markup the line, and the words in the line
:param str line: The line to mark up.
:returns: An HTML form of the line: the characters escaped, the words marked up, and surrounded
in a ``<span>`` element.
:rtype: str'''
if line.strip() == '':
retval = ' <br/>'
else:
cssClass = "line"
# The ">From" is a Unix from, so the line is not a quote
if ((line.lstrip()[0] == '>') and (line.lstrip()[:5] != '>From')):
cssClass += " muted"
# <https://wiki.python.org/moin/EscapingHtml>
escapedLine = escape(line.rstrip(), self.HTML_ESCAPE_TABLE)
markedUpLine = self.markup_words(escapedLine)
r = '<span class="{0}">{1}</span><br/>'
retval = r.format(cssClass, markedUpLine)
assert(retval)
return retval
[docs] def markup_words(self, line):
'''Mark up the words on the line
:param str line: The line to mark up
:returns: The line with the words marked up
:rtype: str'''
rwords = []
for word in line.split(' '):
subWord = None # Word that will be substituted for the current word
# Short-circut if the word is ''. It will be turned back in ' ' when we ``' '.join``
if word:
for matcher in self.matchers:
if matcher.match(word):
subWord = matcher.sub(word)
break
rword = subWord if subWord is not None else word
rwords.append(rword)
retval = ' '.join(rwords)
return retval