1 #makeHTML.py version 0.8 May 1, 2005 Jerry Stratton
3 #part(code="tag" (defaults to paragraph), content="text" style="css style name", id="css id", attributes={named array of attributes for tag}
4 # addAttribute(attributename="name for tag attribute", attributevalue="value for tag attribute")
5 # addPart(code, content, style, id, attributes): adds at end
6 # addPiece(thePart=another part object or "content text")
7 # addPieces(pices=a list of part objects or content texts)
8 # insertPart(code, content, style, id, attributes): inserts at start
10 # make(tab="initial tabs")
11 # makePart(code, content, style, id, attributes): returns a part object
12 # __len__: parts support the len() function; return number of pieces directly contained
13 #snippet(code (defaults to "em"), content, posttext="text that comes directly after tag", pretext="text that comes directly before tag", style, id, attributes)
15 #head(title="text for title of page")
16 #body(title="text for main headline", style, id, attributes)
17 #page(pieces, style, id, attributes)
18 #styleSheet(sheet="url of stylesheet", media="relevance of style sheet")
20 #headline(content="text content" (required), level="numerical level", style, id, attributes)
22 #table(rows=list of data for rows, style, thStyle="css style for table headers", tdStyle="css style for table cells",
23 # trStyle="css style for table rows", tdBlankStyle="css style for blank cells", firstRowHeader=1--if first row is a header row,
24 # firstColumnHeader=1--if first column is a header column, id, attributes)
25 # addRow(rowList=[list of cells or data], celltype="th or td", cellclass="css style of cells", attributes, style)
26 # addRows(rows=[list of list of cells or data], celltype, cellclass, attributes)
28 #tableByColumn(columns=[list of columns], style, thStyle, tdStyle, trStyle, tdBlankStyle, firstRowHeader, firstColumnHeader, id, attributes)
29 # addColumn(columnList=[list of column data or cells], celltype, cellclass, attributes)
30 # addColumns(columns=[list of list of columns or column data], celltype, cellclass, attributes)
31 #tableColumn(column=[list of data or cells for column], celltype, cellclass, firstRowHeader, thStyle, tdBlankStyle, attributes)
32 # addCell(cell="cell or cell content", celltype, cellclass, id, attributes)
33 # addCells(column="list of cells or cell contents", celltype, cellclass, attributes)
34 #tableRow(celltype, row=[list of cells or cell data], style, cellclass, firstColumnHeader, thStyle, id, attributes)
35 # addCell(cell="cell or cell content", celltype, cellclass, colspan="numerical span of cell vertically", rowspan="numerical span of cell horizontally")
36 # addCells(cells=[list of cells or cell content])
39 #linkedList(links=[list of items of the form [url, name]], outer="outer html tag", inner="inner html tag", style="outer css style",
40 # iclass="inner css style", id, attributes)
41 # addLink(link=[url, name])
43 #simpleList(items=[list of text items], outer, inner, defaultname="text for marking default entry", default="text of default entry",
44 # style, iclass, id, attributes)
45 # addItem(item="text of item")
48 #image(src="url of image", alt="alternate text for image", align="alignment", style, id, attributes)
49 #link(content, url, posttext, pretext, style, id, attributes)
51 #form(submitText="text of submit button", pieces, method="submit method", action="form action", submitName="name for submit button", submitAction="javascript for submission"
52 # headline="headline text", headlineLevel (defaults to 2), style, attributes, id)
53 #input(type="type of form input", name="name for input", value="default value for input", size="size for input", maxlength="maximum characters accepted",
54 # style, id, attributes)
55 #select(name, items, default, style, iclass, id, attributes
56 #textinput(name, text, value, size, maxlength, style, id, attributes, type, tableRow=true if this should be a tr row, otherwise it is a paragraph)
60 def __init__(self, code="p", content=None, style=None, id=None, attributes=None):
65 if attributes == None:
68 self.attributes = attributes
69 if isinstance(content, list):
70 self.addPieces(content)
72 self.addPiece(content)
75 return len(self.pieces)
77 def addAttribute(self, attributename, attributevalue):
78 self.attributes[attributename] = attributevalue
80 def addPart(self, code='p', content=None, style=None, id=None, attributes=None):
81 newPart = self.makePart(code, content, style, id, attributes)
82 self.addPiece(newPart)
84 def addPiece(self, thePart):
85 self.pieces.append(thePart)
87 def addPieces(self, theParts):
89 if isinstance(theParts, list):
93 self.addPiece(theParts)
95 def insertPart(self, code='p', content=None, style=None, id=None, attributes=None):
96 newPart = self.makePart(code, content, style, id, attributes)
97 self.insertPiece(newPart)
99 def insertPiece(self, thePart):
100 self.pieces.insert(0, thePart)
102 def make(self, tab="\t"):
103 startHTML = '<' + self.code
105 if (self.attributes):
106 for attribute in self.attributes:
107 content = self.attributes[attribute]
109 startHTML += ' ' + attribute
111 startHTML += ' ' + attribute + '="' + str(content) + '"'
114 startHTML += ' class="' + self.style + '"'
117 startHTML += ' id="' + self.id + '"'
122 partItems = [startHTML]
124 if len(self.pieces) > 1:
133 for piece in self.pieces:
134 if isinstance(piece, str):
135 partItems.append(piece)
136 elif isinstance(piece, int) or isinstance(piece, float):
137 partItems.append(str(piece))
141 partItems.append(piece.make(newtab))
143 code = sep.join(partItems)
144 code += finalSep + '</' + self.code + '>'
151 def makePart(self, code='p', content=None, style=None, id=None, attributes=None):
155 newPart = part(code, content, style, id, attributes)
160 def __init__(self, code="em", content=None, posttext=None, pretext=None, style=None, id=None, attributes=None):
161 part.__init__(self, code, content, style, id, attributes)
162 self.posttext = posttext
163 self.pretext = pretext
165 def make(self, tab=''):
169 snippets.append(self.pretext)
171 snippets.append(part.make(self, tab))
174 snippets.append(self.posttext)
176 return "".join(snippets)
181 def __init__(self, title=None):
182 part.__init__(self, code="head")
184 self.addPiece(part("title", title))
187 def __init__(self, title=None, style=None, id=None, attributes=None):
188 part.__init__(self, code="body", style=style, id=id, attributes=attributes)
190 self.addPiece(headline(title, 1))
193 def __init__(self, pieces=None, style=None, id=None, attributes=None):
194 part.__init__(self, code="html", style=style, id=id, attributes=attributes)
195 if isinstance(pieces, list):
196 self.addPieces(pieces)
197 elif isinstance(pieces, part):
198 self.addPiece(pieces)
200 def make(self, tab=''):
201 pageContent = part.make(self)
203 print 'Content-type: text/html'
208 class styleSheet(part):
209 def __init__(self, sheet, media='all'):
211 attributes['rel'] = "StyleSheet"
212 attributes['href'] = sheet + '.css'
213 attributes['type'] = "text/css"
214 attributes['media'] = media
215 part.__init__(self, code="link", attributes=attributes)
218 #paragraph level parts
219 class headline(part):
220 def __init__(self, content, level=2, style=None, id=None, attributes=None):
221 code = "h"+str(level)
222 part.__init__(self, content=content, style=style, code=code, id=id, attributes=attributes)
228 def __init__(self, rows=None, style=None, thStyle=None, tdStyle=None, trStyle=None, tdBlankStyle=None, firstRowHeader=None, firstColumnHeader=None, id=None, attributes=None):
229 part.__init__(self, code="table", style=style, id=id, attributes=attributes)
230 self.rowclass=trStyle
231 self.cellclass=tdStyle
232 self.cellheaderclass=thStyle
233 self.cellblankclass=tdBlankStyle
234 self.firstRowHeader=firstRowHeader
235 self.firstColumnHeader=firstColumnHeader
239 def addRow(self, rowList, celltype=None, cellclass=None, attributes=None, style=None):
241 if self.firstRowHeader and len(self.pieces) == 0:
243 cellclass=self.cellheaderclass
245 cellclass=self.cellclass
248 style = self.rowclass
250 newRow = tableRow(celltype, rowList, style, cellclass, self.firstColumnHeader, self.cellheaderclass, attributes)
251 self.addPiece(newRow)
253 def addRows(self, rows, cellclass=None, celltype=None, attributes=None):
257 def columnCount(self):
259 for row in self.pieces:
260 if isinstance(row, tableRow):
261 colCount = row.columnCount()
262 maxCount = max(maxCount, colCount)
266 class tableByColumn(table):
267 def __init__(self, columns=None, style=None, thStyle=None, tdStyle=None, trStyle=None, tdBlankStyle=None, firstRowHeader=None, firstColumnHeader=None, id=None, attributes=None):
268 table.__init__(self, [], style, thStyle, tdStyle, trStyle, tdBlankStyle, firstRowHeader, firstColumnHeader, id, attributes)
271 self.addColumns(columns)
273 def addColumn(self, columnList, celltype=None, cellclass=None, attributes=None):
275 if celltype == "th" or (self.firstColumnHeader and len(self.columns) == 0):
277 cellclass=self.cellheaderclass
279 cellclass=self.cellclass
281 newColumn = tableColumn(columnList, celltype, cellclass, self.firstRowHeader, self.cellheaderclass, self.cellblankclass, attributes)
282 self.columns.append(newColumn)
284 def addColumns(self, columns, celltype=None, cellclass=None, attributes=None):
285 for column in columns:
286 self.addColumn(column)
288 def addPiece(self, thePart):
289 if isinstance(thePart, tableColumn):
290 self.columns.append(thePart)
292 part.addPiece(self, thePart)
294 def make(self, tabs):
296 for column in self.columns:
297 rowCount = max(rowCount, len(column.pieces))
300 for cRow in range(rowCount):
302 for column in self.columns:
303 if cRow < len(column.pieces):
304 cell = column.pieces[cRow]
311 myPart = part.make(self, tabs)
315 class tableColumn(part):
316 def __init__(self, column=None, celltype="td", cellclass=None, firstRowHeader=None, thStyle=None, tdBlankStyle=None, attributes=None):
317 part.__init__(self, "column", style=cellclass, attributes=attributes)
321 self.celltype=celltype
323 self.firstRowHeader=firstRowHeader
324 self.cellheaderclass=thStyle
325 self.cellblankclass=tdBlankStyle
328 self.addCells(column)
330 def addCell(self, cell=None, celltype=None, cellclass=None, id=None, attributes=None):
331 if self.cellblankclass and (cell==None or cell==""):
333 cellclass = self.cellblankclass
334 elif self.firstRowHeader and len(self.pieces) == 0:
336 cellclass = self.cellheaderclass
339 celltype = self.celltype
340 if cellclass == None:
341 cellclass = self.style
345 tableCell = part(code=celltype, style=cellclass, content=cell, id=id, attributes=attributes)
346 self.addPiece(tableCell)
348 def addCells(self, column, celltype=None, cellclass=None, attributes=None):
350 self.addCell(cell, celltype, cellclass, attributes=attributes)
353 print "Problem: columns should never be requested to make themselves."
354 print "Columns are not true html structures, and should only be added to tableByColumn parts."
357 class tableRow(part):
358 def __init__(self, celltype="td", row=None, style=None, cellclass=None, firstColumnHeader=None, thStyle=None, id=None, attributes=None):
359 part.__init__(self, "tr", style=style, id=id, attributes=attributes)
360 self.celltype=celltype
361 self.cellclass=cellclass
362 self.firstColumnHeader=firstColumnHeader
363 self.cellheaderclass=thStyle
367 def addCell(self, cell, celltype=None, cellclass=None, colspan=None, rowspan=None):
368 if self.firstColumnHeader and len(self.pieces) == 0:
370 cellclass=self.cellheaderclass
371 elif celltype == None:
372 celltype = self.celltype
378 cellclass=self.cellclass
382 attributes['colspan'] = colspan
384 attributes['rowspan'] = rowspan
389 self.addPiece(part(code=celltype, style=cellclass, content=cell, attributes=attributes))
391 def addCells(self, cells):
395 def columnCount(self):
396 return len(self.pieces)
401 class linkedList(part):
402 def __init__(self, links=None, outer = "ul", inner="li", style=None, iclass=None, id=None, attributes=None):
403 part.__init__(self, code=outer, style=style, id=id, attributes=attributes)
404 self.innercode = inner
405 self.innerstyle = iclass
406 if isinstance(links, list):
409 def addLink(self, link):
411 link = part("a", attributes={"href": url}, content=name)
412 listitem = part(self.innercode, content=link, style=self.innerstyle)
413 self.pieces.append(listitem)
415 def addLinks(self, links):
420 class simpleList(part):
421 def __init__(self, items=None, outer = "ul", inner="li", defaultname=None, default=None, style=None, iclass=None, id=None, attributes=None):
422 part.__init__(self, code=outer, style=style, id=id, attributes=attributes)
423 self.innercode = inner
424 self.innerstyle = iclass
425 self.defaultname = defaultname
427 if isinstance(items, list):
430 def addItem(self, item):
433 if item == self.default:
434 attributes[self.defaultname] = None
436 theItem = part(self.innercode, content=item, style=self.innerstyle, attributes=attributes)
437 self.pieces.append(theItem)
439 def addItems(self, items):
447 def __init__(self, src, alt=None, align=None, style=None, id=None, attributes=None):
448 if attributes == None:
450 attributes['src'] = src
452 attributes['alt'] = alt
454 attributes['align'] = align
456 part.__init__(self, 'img', style=style, id=id, attributes=attributes)
459 def __init__(self, content=None, url=None, posttext=None, pretext=None, style=None, id=None, attributes=None):
461 if attributes == None:
463 attributes['href'] = url
465 snippet.__init__(self, "a", content, posttext, pretext, style, id, attributes)
471 def __init__(self, submitText="Submit", pieces=None, method="get", action='./', submitName = None, submitAction=None, headline=None, headlineLevel = 2, style=None, attributes=None):
472 self.submitText = submitText
473 self.submitName = submitName
475 if attributes == None:
478 attributes['action'] = action
480 attributes['method'] = method
481 if submitAction != None:
482 attributes['onSubmit'] = '"' + submitaction + '"'
484 part.__init__(self, 'form', style=style, attributes=attributes)
487 headcode = "h" + headlineLevel
488 self.addPart(headcode, content=headline)
490 self.addPieces(pieces)
493 def make(self, tab=''):
495 return part.make(self, tab)
498 submitButton = input("submit", value=self.submitText, name=self.submitName)
500 submitButton = input("submit", value=self.submitText)
503 trueForm.addPiece(submitButton)
504 pageContent = trueForm.make(tab)
508 def __init__(self, type, name=None, value=None, size=None, maxlength=None, style=None, id=None, attributes=None):
509 if attributes == None:
512 attributes['type'] = type
514 attributes['name'] = name
516 attributes['value'] = value
518 attributes['size'] = size
520 attributes['maxlength'] = maxlength
522 part.__init__(self, 'input', style=style, id=id, attributes=attributes)
524 class select(simpleList):
525 def __init__(self, name, items=None, default=None, style=None, iclass=None, id=None, attributes=None):
528 attributes['name'] = name
530 simpleList.__init__(self, items, outer='select', inner='option', defaultname='selected', default=default, style=style, iclass=iclass, id=id, attributes=attributes)
532 class textinput(part):
533 def __init__(self, name=None, text=None, value=None, size=None, maxlength=None, style=None, id=None, attributes=None, type="text", tableRow=None):
536 self.field = input(type=type, name=name, value=value, size=size, maxlength=maxlength, style=style, id=id, attributes=attributes)
540 part.__init__(self, 'p', style=style, attributes=attributes)
541 self.addPiece(self.text)
542 self.addPiece(self.field)
544 part.__init__(self, 'tr', style=style, attributes=attributes)
545 self.addPart('th', content=self.text)
546 self.addPart('td', content=self.field)
550 #need some functions for HTML
551 #ought to be somewhere else in Python?
552 #cgi.escape only seems to do <, >, and &
553 from htmlentitydefs import entitydefs
556 entitydefs_inverted = {}
557 for k,v in entitydefs.items():
558 entitydefs_inverted[v] = k
560 needencoding = re.compile('|'.join(entitydefs.values()))
561 alreadyencoded = re.compile('&\w+;|&#[0-9]+;')
563 #encodes any special characters to their HTML equivalents
564 def encode(text, skip=None, once_only=1):
565 # if extra_careful, check to see if this text has already been converted
566 if not (once_only and alreadyencoded.findall(text)):
567 if not isinstance(skip, list):
570 #do ampersands on their own or we might end up converting our conversions
572 text = text.replace('&','&')
576 #grab the characters in the text that need encoding
577 for x in needencoding.findall(text):
578 #and make sure we aren't skipping them
582 for uncoded in needlist:
583 encoded = entitydefs_inverted[uncoded]
584 #if it is not a numerical encoding, we need to do the & and ; ourselves
585 if not encoded.startswith('&#'):
586 encoded = '&%s;'%entitydefs_inverted[uncoded]
588 text = text.replace(uncoded, encoded)