f37 -> f39
[infrastructure.git] / nagios / configurator / makeHTML.py
1 #makeHTML.py version 0.8 May 1, 2005 Jerry Stratton
2 #
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
9 #       insertPiece(thePart)
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)
14 #
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")
19 #
20 #headline(content="text content" (required), level="numerical level", style, id, attributes)
21 #
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)
27 #       columnCount()
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])
37 #       columnCount()
38 #
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])
42 #       addLinks(links)
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")
46 #       addItems(items)
47 #
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)
50 #
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)
57
58 #basic parts
59 class part:
60         def __init__(self, code="p", content=None, style=None, id=None, attributes=None):
61                 self.style = style
62                 self.id=id
63                 self.pieces = []
64                 self.code = code
65                 if attributes == None:
66                         self.attributes = {}
67                 else:
68                         self.attributes = attributes
69                 if isinstance(content, list):
70                         self.addPieces(content)
71                 elif content != None:
72                         self.addPiece(content)
73         
74         def __len__(self):
75                 return len(self.pieces)
76
77         def addAttribute(self, attributename, attributevalue):
78                 self.attributes[attributename] = attributevalue
79
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)
83
84         def addPiece(self, thePart):
85                 self.pieces.append(thePart)
86         
87         def addPieces(self, theParts):
88                 if theParts != None:
89                         if isinstance(theParts, list):
90                                 for part in theParts:
91                                         self.addPiece(part)
92                         else:
93                                 self.addPiece(theParts)
94         
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)
98                 
99         def insertPiece(self, thePart):
100                 self.pieces.insert(0, thePart)
101
102         def make(self, tab="\t"):
103                 startHTML = '<' + self.code
104                 
105                 if (self.attributes):
106                         for attribute in self.attributes:
107                                 content = self.attributes[attribute]
108                                 if content == None:
109                                         startHTML += ' ' + attribute
110                                 else:
111                                         startHTML += ' ' + attribute + '="' + str(content) + '"'
112         
113                 if (self.style):
114                         startHTML += ' class="' + self.style + '"'
115                 
116                 if (self.id):
117                         startHTML += ' id="' + self.id + '"'
118
119                 if self.pieces:
120                         startHTML += '>'
121                         
122                         partItems = [startHTML]
123                         
124                         if len(self.pieces) > 1:
125                                 sep = "\n" + tab
126                                 finalSep = sep[:-1]
127                                 newtab = tab + "\t"
128                         else:
129                                 newtab = tab
130                                 sep = ""
131                                 finalSep = ""
132                         
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))
138                                 elif piece == None:
139                                         partItems.append("")
140                                 else:
141                                         partItems.append(piece.make(newtab))
142                 
143                         code = sep.join(partItems)
144                         code += finalSep + '</' + self.code + '>'
145                         return code
146                         
147                 else:
148                         startHTML += ' />'
149                         return startHTML
150         
151         def makePart(self, code='p', content=None, style=None, id=None, attributes=None):
152                 if content == None:
153                         newPart = part(code)
154                 else:
155                         newPart = part(code, content, style, id, attributes)
156
157                 return newPart
158
159 class snippet(part):
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
164         
165         def make(self, tab=''):
166                 snippets = []
167
168                 if self.pretext:
169                         snippets.append(self.pretext)
170                 
171                 snippets.append(part.make(self, tab))
172                 
173                 if self.posttext:
174                         snippets.append(self.posttext)
175
176                 return "".join(snippets)
177
178 #common body parts
179
180 class head(part):
181         def __init__(self, title=None):
182                 part.__init__(self, code="head")
183                 if title:
184                         self.addPiece(part("title", title))
185
186 class body(part):
187         def __init__(self, title=None, style=None, id=None, attributes=None):
188                 part.__init__(self, code="body", style=style, id=id, attributes=attributes)
189                 if title:
190                         self.addPiece(headline(title, 1))
191
192 class page(part):
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)
199
200         def make(self, tab=''):
201                 pageContent = part.make(self)
202                 
203                 print 'Content-type: text/html'
204                 print ''
205
206                 print pageContent
207
208 class styleSheet(part):
209         def __init__(self, sheet, media='all'):
210                 attributes = {}
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)
216
217
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)
223
224
225
226 #tables
227 class table(part):
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
236                 if rows:
237                         self.addRows(rows)
238
239         def addRow(self, rowList, celltype=None, cellclass=None, attributes=None, style=None):
240                 if cellclass==None:
241                         if self.firstRowHeader and len(self.pieces) == 0:
242                                 celltype="th"
243                                 cellclass=self.cellheaderclass
244                         else:
245                                 cellclass=self.cellclass
246
247                 if style==None:
248                         style = self.rowclass
249
250                 newRow = tableRow(celltype, rowList, style, cellclass, self.firstColumnHeader, self.cellheaderclass, attributes)
251                 self.addPiece(newRow)
252         
253         def addRows(self, rows, cellclass=None, celltype=None, attributes=None):
254                 for row in rows:
255                         self.addRow(row)
256
257         def columnCount(self):
258                 maxCount = 0
259                 for row in self.pieces:
260                         if isinstance(row, tableRow):
261                                 colCount = row.columnCount()
262                                 maxCount = max(maxCount, colCount)
263                 
264                 return maxCount
265
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)
269                 self.columns = []
270                 if columns:
271                         self.addColumns(columns)
272
273         def addColumn(self, columnList, celltype=None, cellclass=None, attributes=None):
274                 if cellclass==None:
275                         if celltype == "th" or (self.firstColumnHeader and len(self.columns) == 0):
276                                 celltype="th"
277                                 cellclass=self.cellheaderclass
278                         else:
279                                 cellclass=self.cellclass
280
281                 newColumn = tableColumn(columnList, celltype, cellclass, self.firstRowHeader, self.cellheaderclass, self.cellblankclass, attributes)
282                 self.columns.append(newColumn)
283
284         def addColumns(self, columns, celltype=None, cellclass=None, attributes=None):
285                 for column in columns:
286                         self.addColumn(column)
287
288         def addPiece(self, thePart):
289                 if isinstance(thePart, tableColumn):
290                         self.columns.append(thePart)
291                 else:
292                         part.addPiece(self, thePart)
293
294         def make(self, tabs):
295                 rowCount = 0
296                 for column in self.columns:
297                         rowCount = max(rowCount, len(column.pieces))
298
299                 if rowCount:
300                         for cRow in range(rowCount):
301                                 row = tableRow()
302                                 for column in self.columns:
303                                         if cRow < len(column.pieces):
304                                                 cell = column.pieces[cRow]
305                                         else:
306                                                 cell = part("td")
307                                         row.addPiece(cell)
308                                 
309                                 self.addPiece(row)
310
311                 myPart = part.make(self, tabs)
312                 return myPart
313
314
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)
318                 if celltype==None:
319                         self.celltype = "td"
320                 else:
321                         self.celltype=celltype
322                 
323                 self.firstRowHeader=firstRowHeader
324                 self.cellheaderclass=thStyle
325                 self.cellblankclass=tdBlankStyle
326                 
327                 if column:
328                         self.addCells(column)
329
330         def addCell(self, cell=None, celltype=None, cellclass=None, id=None, attributes=None):
331                 if self.cellblankclass and (cell==None or cell==""):
332                         celltype="td"
333                         cellclass = self.cellblankclass
334                 elif self.firstRowHeader and len(self.pieces) == 0:
335                         celltype = "th"
336                         cellclass = self.cellheaderclass
337                 else:
338                         if celltype == None:
339                                 celltype = self.celltype
340                         if cellclass == None:
341                                 cellclass = self.style
342                 if cell == None:
343                         cell = ""
344                 
345                 tableCell = part(code=celltype, style=cellclass, content=cell, id=id, attributes=attributes)
346                 self.addPiece(tableCell)
347
348         def addCells(self, column, celltype=None, cellclass=None,  attributes=None):
349                 for cell in column:
350                         self.addCell(cell, celltype, cellclass, attributes=attributes)
351         
352         def make(self):
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."
355
356
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
364                 if row:
365                         self.addCells(row)
366                 
367         def addCell(self, cell, celltype=None, cellclass=None, colspan=None, rowspan=None):
368                 if self.firstColumnHeader and len(self.pieces) == 0:
369                         celltype="th"
370                         cellclass=self.cellheaderclass
371                 elif celltype == None:
372                         celltype = self.celltype
373                 
374                 if celltype == None:
375                         celltype = "td"
376                 
377                 if cellclass==None:
378                         cellclass=self.cellclass
379                 
380                 attributes = {}
381                 if colspan:
382                         attributes['colspan'] = colspan
383                 if rowspan:
384                         attributes['rowspan'] = rowspan
385                 
386                 if cell == None:
387                         cell = ""
388                 
389                 self.addPiece(part(code=celltype, style=cellclass, content=cell, attributes=attributes))
390
391         def addCells(self, cells):
392                 for cell in cells:
393                         self.addCell(cell)
394
395         def columnCount(self):
396                 return len(self.pieces)
397
398
399 #lists
400
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):
407                         self.addLinks(links)
408
409         def addLink(self, link):
410                 [url, name] = 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)
414         
415         def addLinks(self, links):
416                 theLinks = []
417                 for link in links:
418                         self.addLink(link)
419
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
426                 self.default=default
427                 if isinstance(items, list):
428                         self.addItems(items)
429                         
430         def addItem(self, item):
431                 attributes = {}
432                 if self.defaultname:
433                         if item == self.default:
434                                 attributes[self.defaultname] = None
435         
436                 theItem = part(self.innercode, content=item, style=self.innerstyle, attributes=attributes)
437                 self.pieces.append(theItem)
438
439         def addItems(self, items):
440                 theList = []
441                 for item in items:
442                         self.addItem(item)
443
444 #individual pieces
445
446 class image(part):
447         def __init__(self, src, alt=None, align=None, style=None, id=None, attributes=None):
448                 if attributes == None:
449                         attributes = {}
450                 attributes['src'] = src
451                 if alt:
452                         attributes['alt'] = alt
453                 if align:
454                         attributes['align'] = align
455
456                 part.__init__(self, 'img', style=style, id=id, attributes=attributes)
457
458 class link(snippet):
459         def __init__(self, content=None, url=None, posttext=None, pretext=None, style=None, id=None, attributes=None):
460                 if url != None:
461                         if attributes == None:
462                                 attributes = {}
463                         attributes['href'] = url
464
465                 snippet.__init__(self, "a", content, posttext, pretext, style, id, attributes)
466                 
467
468 #forms
469
470 class form(part):
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
474                 self.making = None
475                 if attributes == None:
476                         attributes = {}
477                 if action != None:
478                         attributes['action'] = action
479                 if method != None:
480                         attributes['method'] = method
481                 if submitAction != None:
482                         attributes['onSubmit'] = '"' + submitaction + '"'
483                 
484                 part.__init__(self, 'form', style=style, attributes=attributes)
485                 
486                 if headline != None:
487                         headcode = "h" + headlineLevel
488                         self.addPart(headcode, content=headline)
489                 
490                 self.addPieces(pieces)
491
492
493         def make(self, tab=''):
494                 if self.making:
495                         return part.make(self, tab)
496                 else:
497                         if self.submitName:
498                                 submitButton = input("submit", value=self.submitText, name=self.submitName)
499                         else:
500                                 submitButton = input("submit", value=self.submitText)
501                         trueForm = self
502                         trueForm.making = 1
503                         trueForm.addPiece(submitButton)
504                         pageContent = trueForm.make(tab)
505                         return pageContent
506
507 class input(part):
508         def __init__(self, type, name=None, value=None, size=None, maxlength=None, style=None, id=None, attributes=None):
509                 if attributes == None:
510                         attributes = {}
511
512                 attributes['type'] = type
513                 if name:
514                         attributes['name'] = name
515                 if value!=None:
516                         attributes['value'] = value
517                 if size:
518                         attributes['size'] = size
519                 if maxlength:
520                         attributes['maxlength'] = maxlength
521
522                 part.__init__(self, 'input', style=style, id=id, attributes=attributes)
523
524 class select(simpleList):
525         def __init__(self, name, items=None, default=None, style=None, iclass=None, id=None, attributes=None):
526                 if attributes==None:
527                         attributes={}
528                 attributes['name'] = name
529
530                 simpleList.__init__(self, items, outer='select', inner='option', defaultname='selected', default=default, style=style, iclass=iclass, id=id, attributes=attributes)
531                 
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):
534                 if (text == None):
535                         text = name
536                 self.field = input(type=type, name=name, value=value, size=size, maxlength=maxlength, style=style, id=id, attributes=attributes)
537                 self.text = text
538                 
539                 if tableRow == None:
540                         part.__init__(self, 'p', style=style, attributes=attributes)
541                         self.addPiece(self.text)
542                         self.addPiece(self.field)
543                 else:
544                         part.__init__(self, 'tr', style=style, attributes=attributes)
545                         self.addPart('th', content=self.text)
546                         self.addPart('td', content=self.field)
547
548
549
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
554 import re
555
556 entitydefs_inverted = {}
557 for k,v in entitydefs.items():
558         entitydefs_inverted[v] = k
559
560 needencoding = re.compile('|'.join(entitydefs.values()))
561 alreadyencoded = re.compile('&\w+;|&#[0-9]+;')
562
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):
568                         skip = [skip]
569
570                 #do ampersands on their own or we might end up converting our conversions
571                 if '&' not in skip:
572                         text = text.replace('&','&amp;')
573                         skip.append('&')
574
575                 needlist= []
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
579                         if x not in skip:
580                                 needlist.append(x)
581
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]
587         
588                         text = text.replace(uncoded, encoded)
589
590         return text