#makeHTML.py version 0.8 May 1, 2005 Jerry Stratton
#
#part(code="tag" (defaults to paragraph), content="text" style="css style name", id="css id", attributes={named array of attributes for tag}
# addAttribute(attributename="name for tag attribute", attributevalue="value for tag attribute")
# addPart(code, content, style, id, attributes): adds at end
# addPiece(thePart=another part object or "content text")
# addPieces(pices=a list of part objects or content texts)
# insertPart(code, content, style, id, attributes): inserts at start
# insertPiece(thePart)
# make(tab="initial tabs")
# makePart(code, content, style, id, attributes): returns a part object
# __len__: parts support the len() function; return number of pieces directly contained
#snippet(code (defaults to "em"), content, posttext="text that comes directly after tag", pretext="text that comes directly before tag", style, id, attributes)
#
#head(title="text for title of page")
#body(title="text for main headline", style, id, attributes)
#page(pieces, style, id, attributes)
#styleSheet(sheet="url of stylesheet", media="relevance of style sheet")
#
#headline(content="text content" (required), level="numerical level", style, id, attributes)
#
#table(rows=list of data for rows, style, thStyle="css style for table headers", tdStyle="css style for table cells",
# trStyle="css style for table rows", tdBlankStyle="css style for blank cells", firstRowHeader=1--if first row is a header row,
# firstColumnHeader=1--if first column is a header column, id, attributes)
# addRow(rowList=[list of cells or data], celltype="th or td", cellclass="css style of cells", attributes, style)
# addRows(rows=[list of list of cells or data], celltype, cellclass, attributes)
# columnCount()
#tableByColumn(columns=[list of columns], style, thStyle, tdStyle, trStyle, tdBlankStyle, firstRowHeader, firstColumnHeader, id, attributes)
# addColumn(columnList=[list of column data or cells], celltype, cellclass, attributes)
# addColumns(columns=[list of list of columns or column data], celltype, cellclass, attributes)
#tableColumn(column=[list of data or cells for column], celltype, cellclass, firstRowHeader, thStyle, tdBlankStyle, attributes)
# addCell(cell="cell or cell content", celltype, cellclass, id, attributes)
# addCells(column="list of cells or cell contents", celltype, cellclass, attributes)
#tableRow(celltype, row=[list of cells or cell data], style, cellclass, firstColumnHeader, thStyle, id, attributes)
# addCell(cell="cell or cell content", celltype, cellclass, colspan="numerical span of cell vertically", rowspan="numerical span of cell horizontally")
# addCells(cells=[list of cells or cell content])
# columnCount()
#
#linkedList(links=[list of items of the form [url, name]], outer="outer html tag", inner="inner html tag", style="outer css style",
# iclass="inner css style", id, attributes)
# addLink(link=[url, name])
# addLinks(links)
#simpleList(items=[list of text items], outer, inner, defaultname="text for marking default entry", default="text of default entry",
# style, iclass, id, attributes)
# addItem(item="text of item")
# addItems(items)
#
#image(src="url of image", alt="alternate text for image", align="alignment", style, id, attributes)
#link(content, url, posttext, pretext, style, id, attributes)
#
#form(submitText="text of submit button", pieces, method="submit method", action="form action", submitName="name for submit button", submitAction="javascript for submission"
# headline="headline text", headlineLevel (defaults to 2), style, attributes, id)
#input(type="type of form input", name="name for input", value="default value for input", size="size for input", maxlength="maximum characters accepted",
# style, id, attributes)
#select(name, items, default, style, iclass, id, attributes
#textinput(name, text, value, size, maxlength, style, id, attributes, type, tableRow=true if this should be a tr row, otherwise it is a paragraph)
#basic parts
class part:
def __init__(self, code="p", content=None, style=None, id=None, attributes=None):
self.style = style
self.id=id
self.pieces = []
self.code = code
if attributes == None:
self.attributes = {}
else:
self.attributes = attributes
if isinstance(content, list):
self.addPieces(content)
elif content != None:
self.addPiece(content)
def __len__(self):
return len(self.pieces)
def addAttribute(self, attributename, attributevalue):
self.attributes[attributename] = attributevalue
def addPart(self, code='p', content=None, style=None, id=None, attributes=None):
newPart = self.makePart(code, content, style, id, attributes)
self.addPiece(newPart)
def addPiece(self, thePart):
self.pieces.append(thePart)
def addPieces(self, theParts):
if theParts != None:
if isinstance(theParts, list):
for part in theParts:
self.addPiece(part)
else:
self.addPiece(theParts)
def insertPart(self, code='p', content=None, style=None, id=None, attributes=None):
newPart = self.makePart(code, content, style, id, attributes)
self.insertPiece(newPart)
def insertPiece(self, thePart):
self.pieces.insert(0, thePart)
def make(self, tab="\t"):
startHTML = '<' + self.code
if (self.attributes):
for attribute in self.attributes:
content = self.attributes[attribute]
if content == None:
startHTML += ' ' + attribute
else:
startHTML += ' ' + attribute + '="' + str(content) + '"'
if (self.style):
startHTML += ' class="' + self.style + '"'
if (self.id):
startHTML += ' id="' + self.id + '"'
if self.pieces:
startHTML += '>'
partItems = [startHTML]
if len(self.pieces) > 1:
sep = "\n" + tab
finalSep = sep[:-1]
newtab = tab + "\t"
else:
newtab = tab
sep = ""
finalSep = ""
for piece in self.pieces:
if isinstance(piece, str):
partItems.append(piece)
elif isinstance(piece, int) or isinstance(piece, float):
partItems.append(str(piece))
elif piece == None:
partItems.append("")
else:
partItems.append(piece.make(newtab))
code = sep.join(partItems)
code += finalSep + '' + self.code + '>'
return code
else:
startHTML += ' />'
return startHTML
def makePart(self, code='p', content=None, style=None, id=None, attributes=None):
if content == None:
newPart = part(code)
else:
newPart = part(code, content, style, id, attributes)
return newPart
class snippet(part):
def __init__(self, code="em", content=None, posttext=None, pretext=None, style=None, id=None, attributes=None):
part.__init__(self, code, content, style, id, attributes)
self.posttext = posttext
self.pretext = pretext
def make(self, tab=''):
snippets = []
if self.pretext:
snippets.append(self.pretext)
snippets.append(part.make(self, tab))
if self.posttext:
snippets.append(self.posttext)
return "".join(snippets)
#common body parts
class head(part):
def __init__(self, title=None):
part.__init__(self, code="head")
if title:
self.addPiece(part("title", title))
class body(part):
def __init__(self, title=None, style=None, id=None, attributes=None):
part.__init__(self, code="body", style=style, id=id, attributes=attributes)
if title:
self.addPiece(headline(title, 1))
class page(part):
def __init__(self, pieces=None, style=None, id=None, attributes=None):
part.__init__(self, code="html", style=style, id=id, attributes=attributes)
if isinstance(pieces, list):
self.addPieces(pieces)
elif isinstance(pieces, part):
self.addPiece(pieces)
def make(self, tab=''):
pageContent = part.make(self)
print 'Content-type: text/html'
print ''
print pageContent
class styleSheet(part):
def __init__(self, sheet, media='all'):
attributes = {}
attributes['rel'] = "StyleSheet"
attributes['href'] = sheet + '.css'
attributes['type'] = "text/css"
attributes['media'] = media
part.__init__(self, code="link", attributes=attributes)
#paragraph level parts
class headline(part):
def __init__(self, content, level=2, style=None, id=None, attributes=None):
code = "h"+str(level)
part.__init__(self, content=content, style=style, code=code, id=id, attributes=attributes)
#tables
class table(part):
def __init__(self, rows=None, style=None, thStyle=None, tdStyle=None, trStyle=None, tdBlankStyle=None, firstRowHeader=None, firstColumnHeader=None, id=None, attributes=None):
part.__init__(self, code="table", style=style, id=id, attributes=attributes)
self.rowclass=trStyle
self.cellclass=tdStyle
self.cellheaderclass=thStyle
self.cellblankclass=tdBlankStyle
self.firstRowHeader=firstRowHeader
self.firstColumnHeader=firstColumnHeader
if rows:
self.addRows(rows)
def addRow(self, rowList, celltype=None, cellclass=None, attributes=None, style=None):
if cellclass==None:
if self.firstRowHeader and len(self.pieces) == 0:
celltype="th"
cellclass=self.cellheaderclass
else:
cellclass=self.cellclass
if style==None:
style = self.rowclass
newRow = tableRow(celltype, rowList, style, cellclass, self.firstColumnHeader, self.cellheaderclass, attributes)
self.addPiece(newRow)
def addRows(self, rows, cellclass=None, celltype=None, attributes=None):
for row in rows:
self.addRow(row)
def columnCount(self):
maxCount = 0
for row in self.pieces:
if isinstance(row, tableRow):
colCount = row.columnCount()
maxCount = max(maxCount, colCount)
return maxCount
class tableByColumn(table):
def __init__(self, columns=None, style=None, thStyle=None, tdStyle=None, trStyle=None, tdBlankStyle=None, firstRowHeader=None, firstColumnHeader=None, id=None, attributes=None):
table.__init__(self, [], style, thStyle, tdStyle, trStyle, tdBlankStyle, firstRowHeader, firstColumnHeader, id, attributes)
self.columns = []
if columns:
self.addColumns(columns)
def addColumn(self, columnList, celltype=None, cellclass=None, attributes=None):
if cellclass==None:
if celltype == "th" or (self.firstColumnHeader and len(self.columns) == 0):
celltype="th"
cellclass=self.cellheaderclass
else:
cellclass=self.cellclass
newColumn = tableColumn(columnList, celltype, cellclass, self.firstRowHeader, self.cellheaderclass, self.cellblankclass, attributes)
self.columns.append(newColumn)
def addColumns(self, columns, celltype=None, cellclass=None, attributes=None):
for column in columns:
self.addColumn(column)
def addPiece(self, thePart):
if isinstance(thePart, tableColumn):
self.columns.append(thePart)
else:
part.addPiece(self, thePart)
def make(self, tabs):
rowCount = 0
for column in self.columns:
rowCount = max(rowCount, len(column.pieces))
if rowCount:
for cRow in range(rowCount):
row = tableRow()
for column in self.columns:
if cRow < len(column.pieces):
cell = column.pieces[cRow]
else:
cell = part("td")
row.addPiece(cell)
self.addPiece(row)
myPart = part.make(self, tabs)
return myPart
class tableColumn(part):
def __init__(self, column=None, celltype="td", cellclass=None, firstRowHeader=None, thStyle=None, tdBlankStyle=None, attributes=None):
part.__init__(self, "column", style=cellclass, attributes=attributes)
if celltype==None:
self.celltype = "td"
else:
self.celltype=celltype
self.firstRowHeader=firstRowHeader
self.cellheaderclass=thStyle
self.cellblankclass=tdBlankStyle
if column:
self.addCells(column)
def addCell(self, cell=None, celltype=None, cellclass=None, id=None, attributes=None):
if self.cellblankclass and (cell==None or cell==""):
celltype="td"
cellclass = self.cellblankclass
elif self.firstRowHeader and len(self.pieces) == 0:
celltype = "th"
cellclass = self.cellheaderclass
else:
if celltype == None:
celltype = self.celltype
if cellclass == None:
cellclass = self.style
if cell == None:
cell = ""
tableCell = part(code=celltype, style=cellclass, content=cell, id=id, attributes=attributes)
self.addPiece(tableCell)
def addCells(self, column, celltype=None, cellclass=None, attributes=None):
for cell in column:
self.addCell(cell, celltype, cellclass, attributes=attributes)
def make(self):
print "Problem: columns should never be requested to make themselves."
print "Columns are not true html structures, and should only be added to tableByColumn parts."
class tableRow(part):
def __init__(self, celltype="td", row=None, style=None, cellclass=None, firstColumnHeader=None, thStyle=None, id=None, attributes=None):
part.__init__(self, "tr", style=style, id=id, attributes=attributes)
self.celltype=celltype
self.cellclass=cellclass
self.firstColumnHeader=firstColumnHeader
self.cellheaderclass=thStyle
if row:
self.addCells(row)
def addCell(self, cell, celltype=None, cellclass=None, colspan=None, rowspan=None):
if self.firstColumnHeader and len(self.pieces) == 0:
celltype="th"
cellclass=self.cellheaderclass
elif celltype == None:
celltype = self.celltype
if celltype == None:
celltype = "td"
if cellclass==None:
cellclass=self.cellclass
attributes = {}
if colspan:
attributes['colspan'] = colspan
if rowspan:
attributes['rowspan'] = rowspan
if cell == None:
cell = ""
self.addPiece(part(code=celltype, style=cellclass, content=cell, attributes=attributes))
def addCells(self, cells):
for cell in cells:
self.addCell(cell)
def columnCount(self):
return len(self.pieces)
#lists
class linkedList(part):
def __init__(self, links=None, outer = "ul", inner="li", style=None, iclass=None, id=None, attributes=None):
part.__init__(self, code=outer, style=style, id=id, attributes=attributes)
self.innercode = inner
self.innerstyle = iclass
if isinstance(links, list):
self.addLinks(links)
def addLink(self, link):
[url, name] = link
link = part("a", attributes={"href": url}, content=name)
listitem = part(self.innercode, content=link, style=self.innerstyle)
self.pieces.append(listitem)
def addLinks(self, links):
theLinks = []
for link in links:
self.addLink(link)
class simpleList(part):
def __init__(self, items=None, outer = "ul", inner="li", defaultname=None, default=None, style=None, iclass=None, id=None, attributes=None):
part.__init__(self, code=outer, style=style, id=id, attributes=attributes)
self.innercode = inner
self.innerstyle = iclass
self.defaultname = defaultname
self.default=default
if isinstance(items, list):
self.addItems(items)
def addItem(self, item):
attributes = {}
if self.defaultname:
if item == self.default:
attributes[self.defaultname] = None
theItem = part(self.innercode, content=item, style=self.innerstyle, attributes=attributes)
self.pieces.append(theItem)
def addItems(self, items):
theList = []
for item in items:
self.addItem(item)
#individual pieces
class image(part):
def __init__(self, src, alt=None, align=None, style=None, id=None, attributes=None):
if attributes == None:
attributes = {}
attributes['src'] = src
if alt:
attributes['alt'] = alt
if align:
attributes['align'] = align
part.__init__(self, 'img', style=style, id=id, attributes=attributes)
class link(snippet):
def __init__(self, content=None, url=None, posttext=None, pretext=None, style=None, id=None, attributes=None):
if url != None:
if attributes == None:
attributes = {}
attributes['href'] = url
snippet.__init__(self, "a", content, posttext, pretext, style, id, attributes)
#forms
class form(part):
def __init__(self, submitText="Submit", pieces=None, method="get", action='./', submitName = None, submitAction=None, headline=None, headlineLevel = 2, style=None, attributes=None):
self.submitText = submitText
self.submitName = submitName
self.making = None
if attributes == None:
attributes = {}
if action != None:
attributes['action'] = action
if method != None:
attributes['method'] = method
if submitAction != None:
attributes['onSubmit'] = '"' + submitaction + '"'
part.__init__(self, 'form', style=style, attributes=attributes)
if headline != None:
headcode = "h" + headlineLevel
self.addPart(headcode, content=headline)
self.addPieces(pieces)
def make(self, tab=''):
if self.making:
return part.make(self, tab)
else:
if self.submitName:
submitButton = input("submit", value=self.submitText, name=self.submitName)
else:
submitButton = input("submit", value=self.submitText)
trueForm = self
trueForm.making = 1
trueForm.addPiece(submitButton)
pageContent = trueForm.make(tab)
return pageContent
class input(part):
def __init__(self, type, name=None, value=None, size=None, maxlength=None, style=None, id=None, attributes=None):
if attributes == None:
attributes = {}
attributes['type'] = type
if name:
attributes['name'] = name
if value!=None:
attributes['value'] = value
if size:
attributes['size'] = size
if maxlength:
attributes['maxlength'] = maxlength
part.__init__(self, 'input', style=style, id=id, attributes=attributes)
class select(simpleList):
def __init__(self, name, items=None, default=None, style=None, iclass=None, id=None, attributes=None):
if attributes==None:
attributes={}
attributes['name'] = name
simpleList.__init__(self, items, outer='select', inner='option', defaultname='selected', default=default, style=style, iclass=iclass, id=id, attributes=attributes)
class textinput(part):
def __init__(self, name=None, text=None, value=None, size=None, maxlength=None, style=None, id=None, attributes=None, type="text", tableRow=None):
if (text == None):
text = name
self.field = input(type=type, name=name, value=value, size=size, maxlength=maxlength, style=style, id=id, attributes=attributes)
self.text = text
if tableRow == None:
part.__init__(self, 'p', style=style, attributes=attributes)
self.addPiece(self.text)
self.addPiece(self.field)
else:
part.__init__(self, 'tr', style=style, attributes=attributes)
self.addPart('th', content=self.text)
self.addPart('td', content=self.field)
#need some functions for HTML
#ought to be somewhere else in Python?
#cgi.escape only seems to do <, >, and &
from htmlentitydefs import entitydefs
import re
entitydefs_inverted = {}
for k,v in entitydefs.items():
entitydefs_inverted[v] = k
needencoding = re.compile('|'.join(entitydefs.values()))
alreadyencoded = re.compile('&\w+;|[0-9]+;')
#encodes any special characters to their HTML equivalents
def encode(text, skip=None, once_only=1):
# if extra_careful, check to see if this text has already been converted
if not (once_only and alreadyencoded.findall(text)):
if not isinstance(skip, list):
skip = [skip]
#do ampersands on their own or we might end up converting our conversions
if '&' not in skip:
text = text.replace('&','&')
skip.append('&')
needlist= []
#grab the characters in the text that need encoding
for x in needencoding.findall(text):
#and make sure we aren't skipping them
if x not in skip:
needlist.append(x)
for uncoded in needlist:
encoded = entitydefs_inverted[uncoded]
#if it is not a numerical encoding, we need to do the & and ; ourselves
if not encoded.startswith(''):
encoded = '&%s;'%entitydefs_inverted[uncoded]
text = text.replace(uncoded, encoded)
return text