diff options
Diffstat (limited to 'Mailman/htmlformat.py')
| -rw-r--r-- | Mailman/htmlformat.py | 670 |
1 files changed, 0 insertions, 670 deletions
diff --git a/Mailman/htmlformat.py b/Mailman/htmlformat.py deleted file mode 100644 index fa3f4d1a4..000000000 --- a/Mailman/htmlformat.py +++ /dev/null @@ -1,670 +0,0 @@ -# Copyright (C) 1998-2008 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -"""Library for program-based construction of an HTML documents. - -Encapsulate HTML formatting directives in classes that act as containers -for python and, recursively, for nested HTML formatting objects. -""" - -from Mailman import Defaults -from Mailman import Utils -from Mailman import Version -from Mailman.configuration import config -from Mailman.i18n import _ - -SPACE = ' ' -EMPTYSTRING = '' -NL = '\n' - - - -# Format an arbitrary object. -def HTMLFormatObject(item, indent): - "Return a presentation of an object, invoking their Format method if any." - if hasattr(item, 'Format'): - return item.Format(indent) - if isinstance(item, basestring): - return item - return str(item) - -def CaseInsensitiveKeyedDict(d): - result = {} - for (k,v) in d.items(): - result[k.lower()] = v - return result - -# Given references to two dictionaries, copy the second dictionary into the -# first one. -def DictMerge(destination, fresh_dict): - for (key, value) in fresh_dict.items(): - destination[key] = value - -class Table: - def __init__(self, **table_opts): - self.cells = [] - self.cell_info = {} - self.row_info = {} - self.opts = table_opts - - def AddOptions(self, opts): - DictMerge(self.opts, opts) - - # Sets all of the cells. It writes over whatever cells you had there - # previously. - - def SetAllCells(self, cells): - self.cells = cells - - # Add a new blank row at the end - def NewRow(self): - self.cells.append([]) - - # Add a new blank cell at the end - def NewCell(self): - self.cells[-1].append('') - - def AddRow(self, row): - self.cells.append(row) - - def AddCell(self, cell): - self.cells[-1].append(cell) - - def AddCellInfo(self, row, col, **kws): - kws = CaseInsensitiveKeyedDict(kws) - if not self.cell_info.has_key(row): - self.cell_info[row] = { col : kws } - elif self.cell_info[row].has_key(col): - DictMerge(self.cell_info[row], kws) - else: - self.cell_info[row][col] = kws - - def AddRowInfo(self, row, **kws): - kws = CaseInsensitiveKeyedDict(kws) - if not self.row_info.has_key(row): - self.row_info[row] = kws - else: - DictMerge(self.row_info[row], kws) - - # What's the index for the row we just put in? - def GetCurrentRowIndex(self): - return len(self.cells)-1 - - # What's the index for the col we just put in? - def GetCurrentCellIndex(self): - return len(self.cells[-1])-1 - - def ExtractCellInfo(self, info): - valid_mods = ['align', 'valign', 'nowrap', 'rowspan', 'colspan', - 'bgcolor'] - output = '' - - for (key, val) in info.items(): - if not key in valid_mods: - continue - if key == 'nowrap': - output = output + ' NOWRAP' - continue - else: - output = output + ' %s="%s"' % (key.upper(), val) - - return output - - def ExtractRowInfo(self, info): - valid_mods = ['align', 'valign', 'bgcolor'] - output = '' - - for (key, val) in info.items(): - if not key in valid_mods: - continue - output = output + ' %s="%s"' % (key.upper(), val) - - return output - - def ExtractTableInfo(self, info): - valid_mods = ['align', 'width', 'border', 'cellspacing', 'cellpadding', - 'bgcolor'] - - output = '' - - for (key, val) in info.items(): - if not key in valid_mods: - continue - if key == 'border' and val == None: - output = output + ' BORDER' - continue - else: - output = output + ' %s="%s"' % (key.upper(), val) - - return output - - def FormatCell(self, row, col, indent): - try: - my_info = self.cell_info[row][col] - except: - my_info = None - - output = '\n' + ' '*indent + '<td' - if my_info: - output = output + self.ExtractCellInfo(my_info) - item = self.cells[row][col] - item_format = HTMLFormatObject(item, indent+4) - output = '%s>%s</td>' % (output, item_format) - return output - - def FormatRow(self, row, indent): - try: - my_info = self.row_info[row] - except: - my_info = None - - output = '\n' + ' '*indent + '<tr' - if my_info: - output = output + self.ExtractRowInfo(my_info) - output = output + '>' - - for i in range(len(self.cells[row])): - output = output + self.FormatCell(row, i, indent + 2) - - output = output + '\n' + ' '*indent + '</tr>' - - return output - - def Format(self, indent=0): - output = '\n' + ' '*indent + '<table' - output = output + self.ExtractTableInfo(self.opts) - output = output + '>' - - for i in range(len(self.cells)): - output = output + self.FormatRow(i, indent + 2) - - output = output + '\n' + ' '*indent + '</table>\n' - - return output - - -class Link: - def __init__(self, href, text, target=None): - self.href = href - self.text = text - self.target = target - - def Format(self, indent=0): - texpr = "" - if self.target != None: - texpr = ' target="%s"' % self.target - return '<a href="%s"%s>%s</a>' % (HTMLFormatObject(self.href, indent), - texpr, - HTMLFormatObject(self.text, indent)) - -class FontSize: - """FontSize is being deprecated - use FontAttr(..., size="...") instead.""" - def __init__(self, size, *items): - self.items = list(items) - self.size = size - - def Format(self, indent=0): - output = '<font size="%s">' % self.size - for item in self.items: - output = output + HTMLFormatObject(item, indent) - output = output + '</font>' - return output - -class FontAttr: - """Present arbitrary font attributes.""" - def __init__(self, *items, **kw): - self.items = list(items) - self.attrs = kw - - def Format(self, indent=0): - seq = [] - for k, v in self.attrs.items(): - seq.append('%s="%s"' % (k, v)) - output = '<font %s>' % SPACE.join(seq) - for item in self.items: - output = output + HTMLFormatObject(item, indent) - output = output + '</font>' - return output - - -class Container: - def __init__(self, *items): - if not items: - self.items = [] - else: - self.items = items - - def AddItem(self, obj): - self.items.append(obj) - - def Format(self, indent=0): - output = [] - for item in self.items: - output.append(HTMLFormatObject(item, indent)) - return EMPTYSTRING.join(output) - - -class Label(Container): - align = 'right' - - def __init__(self, *items): - Container.__init__(self, *items) - - def Format(self, indent=0): - return ('<div align="%s">' % self.align) + \ - Container.Format(self, indent) + \ - '</div>' - - -# My own standard document template. YMMV. -# something more abstract would be more work to use... - -class Document(Container): - title = None - language = None - bgcolor = Defaults.WEB_BG_COLOR - suppress_head = 0 - - def set_language(self, lang=None): - self.language = lang - - def set_bgcolor(self, color): - self.bgcolor = color - - def SetTitle(self, title): - self.title = title - - def Format(self, indent=0, **kws): - charset = 'us-ascii' - if self.language: - charset = Utils.GetCharSet(self.language) - output = ['Content-Type: text/html; charset=%s\n' % charset] - if not self.suppress_head: - kws.setdefault('bgcolor', self.bgcolor) - tab = ' ' * indent - output.extend([tab, - '<HTML>', - '<HEAD>' - ]) - if config.IMAGE_LOGOS: - output.append('<LINK REL="SHORTCUT ICON" HREF="%s">' % - (config.IMAGE_LOGOS + config.SHORTCUT_ICON)) - # Hit all the bases - output.append('<META http-equiv="Content-Type" ' - 'content="text/html; charset=%s">' % charset) - if self.title: - output.append('%s<TITLE>%s</TITLE>' % (tab, self.title)) - output.append('%s</HEAD>' % tab) - quals = [] - # Default link colors - if config.WEB_VLINK_COLOR: - kws.setdefault('vlink', config.WEB_VLINK_COLOR) - if config.WEB_ALINK_COLOR: - kws.setdefault('alink', config.WEB_ALINK_COLOR) - if config.WEB_LINK_COLOR: - kws.setdefault('link', config.WEB_LINK_COLOR) - for k, v in kws.items(): - quals.append('%s="%s"' % (k, v)) - output.append('%s<BODY %s>' % (tab, SPACE.join(quals))) - # Always do this... - output.append(Container.Format(self, indent)) - if not self.suppress_head: - output.append('%s</BODY>' % tab) - output.append('%s</HTML>' % tab) - return NL.join(output).encode(charset, 'replace') - - def addError(self, errmsg, tag=None): - if tag is None: - tag = _('Error: ') - self.AddItem(Header(3, Bold(FontAttr( - _(tag), color=config.WEB_ERROR_COLOR, size='+2')).Format() + - Italic(errmsg).Format())) - - -class HeadlessDocument(Document): - """Document without head section, for templates that provide their own.""" - suppress_head = 1 - - -class StdContainer(Container): - def Format(self, indent=0): - # If I don't start a new I ignore indent - output = '<%s>' % self.tag - output = output + Container.Format(self, indent) - output = '%s</%s>' % (output, self.tag) - return output - - -class QuotedContainer(Container): - def Format(self, indent=0): - # If I don't start a new I ignore indent - output = '<%s>%s</%s>' % ( - self.tag, - Utils.websafe(Container.Format(self, indent)), - self.tag) - return output - -class Header(StdContainer): - def __init__(self, num, *items): - self.items = items - self.tag = 'h%d' % num - -class Address(StdContainer): - tag = 'address' - -class Underline(StdContainer): - tag = 'u' - -class Bold(StdContainer): - tag = 'strong' - -class Italic(StdContainer): - tag = 'em' - -class Preformatted(QuotedContainer): - tag = 'pre' - -class Subscript(StdContainer): - tag = 'sub' - -class Superscript(StdContainer): - tag = 'sup' - -class Strikeout(StdContainer): - tag = 'strike' - -class Center(StdContainer): - tag = 'center' - -class Form(Container): - def __init__(self, action='', method='POST', encoding=None, *items): - apply(Container.__init__, (self,) + items) - self.action = action - self.method = method - self.encoding = encoding - - def set_action(self, action): - self.action = action - - def Format(self, indent=0): - spaces = ' ' * indent - encoding = '' - if self.encoding: - encoding = 'enctype="%s"' % self.encoding - output = '\n%s<FORM action="%s" method="%s" %s>\n' % ( - spaces, self.action, self.method, encoding) - output = output + Container.Format(self, indent+2) - output = '%s\n%s</FORM>\n' % (output, spaces) - return output - - -class InputObj: - def __init__(self, name, ty, value, checked, **kws): - self.name = name - self.type = ty - self.value = value - self.checked = checked - self.kws = kws - - def Format(self, indent=0): - output = ['<INPUT name="%s" type="%s" value="%s"' % - (self.name, self.type, self.value)] - for item in self.kws.items(): - output.append('%s="%s"' % item) - if self.checked: - output.append('CHECKED') - output.append('>') - return SPACE.join(output) - - -class SubmitButton(InputObj): - def __init__(self, name, button_text): - InputObj.__init__(self, name, "SUBMIT", button_text, checked=0) - -class PasswordBox(InputObj): - def __init__(self, name, value='', size=Defaults.TEXTFIELDWIDTH): - InputObj.__init__(self, name, "PASSWORD", value, checked=0, size=size) - -class TextBox(InputObj): - def __init__(self, name, value='', size=Defaults.TEXTFIELDWIDTH): - InputObj.__init__(self, name, "TEXT", value, checked=0, size=size) - -class Hidden(InputObj): - def __init__(self, name, value=''): - InputObj.__init__(self, name, 'HIDDEN', value, checked=0) - -class TextArea: - def __init__(self, name, text='', rows=None, cols=None, wrap='soft', - readonly=0): - self.name = name - self.text = text - self.rows = rows - self.cols = cols - self.wrap = wrap - self.readonly = readonly - - def Format(self, indent=0): - output = '<TEXTAREA NAME=%s' % self.name - if self.rows: - output += ' ROWS=%s' % self.rows - if self.cols: - output += ' COLS=%s' % self.cols - if self.wrap: - output += ' WRAP=%s' % self.wrap - if self.readonly: - output += ' READONLY' - output += '>%s</TEXTAREA>' % self.text - return output - -class FileUpload(InputObj): - def __init__(self, name, rows=None, cols=None, **kws): - apply(InputObj.__init__, (self, name, 'FILE', '', 0), kws) - -class RadioButton(InputObj): - def __init__(self, name, value, checked=0, **kws): - apply(InputObj.__init__, (self, name, 'RADIO', value, checked), kws) - -class CheckBox(InputObj): - def __init__(self, name, value, checked=0, **kws): - apply(InputObj.__init__, (self, name, "CHECKBOX", value, checked), kws) - -class VerticalSpacer: - def __init__(self, size=10): - self.size = size - def Format(self, indent=0): - output = '<spacer type="vertical" height="%d">' % self.size - return output - -class WidgetArray: - Widget = None - - def __init__(self, name, button_names, checked, horizontal, values): - self.name = name - self.button_names = button_names - self.checked = checked - self.horizontal = horizontal - self.values = values - assert len(values) == len(button_names) - # Don't assert `checked' because for RadioButtons it is a scalar while - # for CheckedBoxes it is a vector. Subclasses will assert length. - - def ischecked(self, i): - raise NotImplemented - - def Format(self, indent=0): - t = Table(cellspacing=5) - items = [] - for i, name, value in zip(range(len(self.button_names)), - self.button_names, - self.values): - ischecked = (self.ischecked(i)) - item = self.Widget(self.name, value, ischecked).Format() + name - items.append(item) - if not self.horizontal: - t.AddRow(items) - items = [] - if self.horizontal: - t.AddRow(items) - return t.Format(indent) - -class RadioButtonArray(WidgetArray): - Widget = RadioButton - - def __init__(self, name, button_names, checked=None, horizontal=1, - values=None): - if values is None: - values = range(len(button_names)) - # BAW: assert checked is a scalar... - WidgetArray.__init__(self, name, button_names, checked, horizontal, - values) - - def ischecked(self, i): - return self.checked == i - -class CheckBoxArray(WidgetArray): - Widget = CheckBox - - def __init__(self, name, button_names, checked=None, horizontal=0, - values=None): - if checked is None: - checked = [0] * len(button_names) - else: - assert len(checked) == len(button_names) - if values is None: - values = range(len(button_names)) - WidgetArray.__init__(self, name, button_names, checked, horizontal, - values) - - def ischecked(self, i): - return self.checked[i] - -class UnorderedList(Container): - def Format(self, indent=0): - spaces = ' ' * indent - output = '\n%s<ul>\n' % spaces - for item in self.items: - output = output + '%s<li>%s\n' % \ - (spaces, HTMLFormatObject(item, indent + 2)) - output = output + '%s</ul>\n' % spaces - return output - -class OrderedList(Container): - def Format(self, indent=0): - spaces = ' ' * indent - output = '\n%s<ol>\n' % spaces - for item in self.items: - output = output + '%s<li>%s\n' % \ - (spaces, HTMLFormatObject(item, indent + 2)) - output = output + '%s</ol>\n' % spaces - return output - -class DefinitionList(Container): - def Format(self, indent=0): - spaces = ' ' * indent - output = '\n%s<dl>\n' % spaces - for dt, dd in self.items: - output = output + '%s<dt>%s\n<dd>%s\n' % \ - (spaces, HTMLFormatObject(dt, indent+2), - HTMLFormatObject(dd, indent+2)) - output = output + '%s</dl>\n' % spaces - return output - - - -# Logo constants -# -# These are the URLs which the image logos link to. The Mailman home page now -# points at the gnu.org site instead of the www.list.org mirror. - -PYTHON_URL = 'http://www.python.org/' -GNU_URL = 'http://www.gnu.org/' - -# The names of the image logo files. These are concatentated onto -# config.IMAGE_LOGOS (not urljoined). -DELIVERED_BY = 'mailman.jpg' -PYTHON_POWERED = 'PythonPowered.png' -GNU_HEAD = 'gnu-head-tiny.jpg' - - -def MailmanLogo(): - t = Table(border=0, width='100%') - if config.IMAGE_LOGOS: - def logo(file): - return config.IMAGE_LOGOS + file - mmlink = '<img src="%s" alt="Delivered by Mailman" border=0>' \ - '<br>version %s' % (logo(DELIVERED_BY), Version.VERSION) - pylink = '<img src="%s" alt="Python Powered" border=0>' % \ - logo(PYTHON_POWERED) - gnulink = '<img src="%s" alt="GNU\'s Not Unix" border=0>' % \ - logo(GNU_HEAD) - t.AddRow([mmlink, pylink, gnulink]) - else: - # use only textual links - version = Version.VERSION - mmlink = Link(config.MAILMAN_URL, - _('Delivered by Mailman<br>version %(version)s')) - pylink = Link(PYTHON_URL, _('Python Powered')) - gnulink = Link(GNU_URL, _("Gnu's Not Unix")) - t.AddRow([mmlink, pylink, gnulink]) - return t - - -class SelectOptions: - def __init__(self, varname, values, legend, - selected=0, size=1, multiple=None): - self.varname = varname - self.values = values - self.legend = legend - self.size = size - self.multiple = multiple - # we convert any type to tuple, commas are needed - if not multiple: - if isinstance(selected, int): - self.selected = (selected,) - elif isinstance(selected, tuple): - self.selected = (selected[0],) - elif isinstance(selected, list): - self.selected = (selected[0],) - else: - self.selected = (0,) - - def Format(self, indent=0): - spaces = " " * indent - items = min( len(self.values), len(self.legend) ) - - # jcrey: If there is no argument, we return nothing to avoid errors - if items == 0: - return "" - - text = "\n" + spaces + "<Select name=\"%s\"" % self.varname - if self.size > 1: - text = text + " size=%d" % self.size - if self.multiple: - text = text + " multiple" - text = text + ">\n" - - for i in range(items): - if i in self.selected: - checked = " Selected" - else: - checked = "" - - opt = " <option value=\"%s\"%s> %s </option>" % ( - self.values[i], checked, self.legend[i]) - text = text + spaces + opt + "\n" - - return text + spaces + '</Select>' |
