# # html_util # # Utility functions to generate (basic) HTML output from CGI # scripts. # # author: Asfandyar Qureshi # copying: MIT license import sys HTML_HEADER=\ """ <html> <head> <title> %s </title> <META HTTP-EQUIV="pragma" CONTENT="no-cache"> <style> <!-- body { background-color: #ffffff; font-family: verdana, arial, helvetica, sans-serif; } div { font-size: 13px; } p { font-size: 13px; } ol { font-size: 13px; } ul { font-size: 13px; } h1 { font-size: 24px; font-weight: bold; } h2 { font-size: 18px; font-weight: bold; border-bottom: 2px solid #000000; } h3 { font-size: 15px; font-weight: bold; } pre { font-family: "courier new", courier, mono; color: #400040; font-size: 13px; font-weight: bold; } li { list-style: square; } div { padding-left:16px; padding-top:8px; padding-bottom:8px; padding-right:16px; text-align: left } div.white { border: 1px solid #bbbbbb; background: #ffffff; } div.gray { border: 1px solid #bbbbbb; background: #eeeeee; } div.yellow { border: 1px solid #bbbbbb; background: #ffffe4; } div.green { border: 1px solid #bbbbbb; background: #ddffaa; } div.orange { border: 1px solid #bbbbbb; background: #ffe787; } div.purple { border: 1px solid #000000; color: #ffffff; background: #491c3d; } div.darkred { border: 1px solid #000000; color: #ffffff; background: #8a0a0a; } div.darkgray { border: 1px solid #000000; color: #ffffff; background: #aaaaaa; } div.black { color: #ffffff; background: #000000; } //--> </style> </head> <body> <div style="padding-right: 32px; padding-left: 32px;"> """ HTML_FOOTER=\ """ </div> </body> </html> """ class HTMLDocument: """ A HTML document. Provides functions for constructing a HTML documents with stylized text, forms, and images. Also provides functions for outputting that HTML from a CGI script. """ # body : list of strings (represents a HTML fragment) def __init__(self, title): """ Creates an empty HTML document with the given title. """ self.body = [HTML_HEADER % title] def print_html(self): """ Outputs the HTML. requires: for valid HTML, all begun tags should be ended. """ if not self.body[-1] == HTML_FOOTER: # make sure HTML footer is there self.body.append(HTML_FOOTER) #print 'Content-type: text/html\n\n' sys.stdout.write('Content-type: text/html\n\n') for fragment in self.body: sys.stdout.write(fragment) #print fragment, def _was_printed(self): """ Returns True if print_html has been called at least once, False otherwise. """ return (self.body[-1] == HTML_FOOTER) # # helper functions # def _add_html_escapes(self, text): text = text.replace('&', '&') text = text.replace('"', '"') text = text.replace("'", ''') text = text.replace('<', '<') text = text.replace('>', '>') return text # # basic text stuff # def write_text(self, text, color=None, size=None, bold=False, italic=False, underlined=False, typewriter=False): """ Writes a fragment of formatted text. The following formatting options exist: color: string (e.g., 'red', 'blue', 'orange', or html hex '#ffffff' size: string (e.g., '12px', '10pt') bold: boolean italic: boolean typewriter: boolean """ html="" # add format tags if bold: html += "<b>" if italic: html += "<i>" if underlined: html += "<u>" if typewriter: html += "<tt>" # style (size + color) if size or color: html += "<font style='" if size: html += "font-size: %s;" % str(size) if color: html += "color: %s;" % str(color) html += "'>" # HTML escapes text = self._add_html_escapes(text) # add text html += text # close style if size or color: html += "</font>" # close format tags if typewriter: html += "</tt>" if underlined: html += "</u>" if italic: html += "</i>" if bold: html += "</b>" # add to document self.body.append(html) def write_pre_text(self, text): """ Write pre-formatted text (e.g., python code). """ html ="<pre>%s</pre>" % text self.body.append(html) def new_paragraph(self): """ Starts a new paragraph in the HTML. """ self.body.append("\n<p>\n") def newline(self): self.body.append("<br>\n") def new_section(self, section_title): """ Starts a new section in the HTML. """ txt = self._add_html_escapes(section_title) self.body.append("\n<h1>%s</h1>\n" % txt) def new_subsection(self, section_title): """ Starts a new sub-section in the HTML. """ txt = self._add_html_escapes(section_title) self.body.append("\n<h2>%s</h2>\n" % txt) def new_subsubsection(self, section_title): """ Starts a new sub-sub-section in the HTML. """ txt = self._add_html_escapes(section_title) self.body.append("\n<h3>%s</h3>\n" % txt) # # divs and align # def begin_center(self): """ Begin a block horizontally centered. You will need to call end_center. """ self.body.append("\n<center>\n") def end_center(self): """ Begin a block horizontally centered. You will need to call end_center. """ self.body.append("\n</center>\n") def begin_div_block(self, type=None, width=None): """ Begin a division with some specific formatting style and width. valid values for type: None: white background, no borders 'white': white backround box 'gray': light gray background box 'yellow': pale yellow background box 'green': green background box 'orange': orange background box 'purple': dark purple box with white text 'darkred': dark red background box, white foreground 'darkgray':dark gray background box, white foreground 'black': black background box, white foreground width: in percent or pixels (string), e.g., 100% or 100px """ if type: type = str(type) if not type in ['white', 'gray', 'yellow', 'green', 'orange', 'purple', 'darkred', 'darkgray', 'black']: raise ValueError(type) html = "\n<div" if type: html += " class='%s'" % type if width: html += " style='width:%s'" % str(width) html += ">\n" self.body.append(html) def end_div_block(self): self.body.append("\n</div>\n") # # lists # def write_numbered_list(self, list): """ Adds the elements of the list as a numbered list, with each element on a new line. """ html="\n<ol>\n" for item in list: txt = self._add_html_escapes(str(item)) html += "<li>%s</li>\n" % txt html += "</ol>\n" self.body.append(html) def write_bullet_list(self, list): """ Adds the elements of the list as a bullet-ed list, with each element on a new line. """ html="\n<ul>\n" for item in list: txt = self._add_html_escapes(str(item)) html += "<li>%s</li>\n" % txt html += "</ul>\n" self.body.append(html) # # links # def begin_linked_part(self, link_url): """ Starts a part of the HTML that links to another document. You will need to call end_linked_part. """ self.body.append("<a href='%s'>" % link_url) def end_linked_part(self): """ Ends a link. """ self.body.append("</a>") # # images # def add_image(self, image_url, image_text=None, image_width=None, image_height=None): """ Adds an image with some descriptive text, in case the image cannot be loaded. image_width, image_height: (string) pixels or percent, e.g. 150px or 70% """ html = "\n<img src='%s'" % image_url if image_text: html += " alt='%s'" % str(image_text) if image_width: html += " width='%s'" % str(image_width) if image_height: html += " height='%s'" % str(image_height) html += ">\n" self.body.append(html) # # forms # def begin_form(self, action): """ Begins a form. You can add as many inputs to the form as you want, but you must eventually end the form action: the action to undertake when the user submits the form. action can either be 'mailto:' followed by an email address, or it can be the name of a script that will be invoked with a HTTP post. """ if action[:7].lower() == 'mailto:': self.body.append("\n<form action='%s' method='post' enctype='text/plain'>\n" % action) else: self.body.append("\n<form action='%s' method='post' enctype='multipart/form-data'>\n" % action) def end_form(self): self.body.append("\n</form>") def form_add_button_submit(self, button_caption="Submit"): html = "<input type='submit' value='%s'>\n" % button_caption self.body.append(html) def form_add_button_reset(self, button_caption="Reset"): html = "<input type='reset' value='%s'>" % button_caption self.body.append(html) def form_add_field_text(self, id, default_value="", size="60"): """ A text field accepts a single-line text input from the user. This is useful for asking the user for things like email and names, etc. default_value: initial text size: width of text box, in characters """ default_value = self._add_html_escapes(default_value) html="<input type='text' name='%s' value='%s'>\n" % (id, str(default_value)) self.body.append(html) def form_add_field_checkbox(self, id, checked=False): """ A checkbox field is either true or false. """ html="<input type='checkbox' name='%s'" % id if checked: html += " checked" html += ">\n" self.body.append(html) def form_add_field_textarea(self, id, rows=5, cols=60, default_value=""): """ A text-area field accepts a multi-line text input. This is useful for asking more open-ended questions, e.g., comments. """ default_value = self._add_html_escapes(default_value) html="<textarea name='%s' rows='%s' cols='%s'>\n%s\n</textarea>\n" % (id, str(rows), str(cols), str(default_value)) self.body.append(html) def form_add_field_multichoice(self, id, choice_id=[], choices=[], selected=None, newlines=True): """ Adds a multiple choice field, as a set of radio inputs. requires: len(choice_id) == len(choices) choice_id: the internal identifier for each option. this indentifier will show up in the submitted form. choices: the text displayed for each choice selected: None or the choice_id that should be initially selected newlines: if this is True, each option is on a new line. """ html="" for i in range(len(choice_id)): txt = self._add_html_escapes(choices[i]) #html += "<input type='radio' name='%s' value='%s'> %s" % (id, str(choice_id[i]), txt) html += "<input type='radio' name='%s' value='%s'" % (id, str(choice_id[i])) if choice_id[i] == selected: html += " checked" html += "> %s" % txt if newlines: html += "<br>\n" self.body.append(html) def form_add_field_dropdown_choice(self, id, choice_id=[], choices=[]): """ Adds a multiple choice field, as a drop-down list. requires: len(choice_id) == len(choices) choice_id: the internal identifier for each option. this indentifier will show up in the submitted form. choices: the text displayed for each choice """ html="<select name='%s'>" % id for i in range(len(choice_id)): txt = self._add_html_escapes(choices[i]) html += "<option value='%s'>%s</option>\n" % (str(choice_id[i]), txt) html += "</select>\n" self.body.append(html) def form_add_field_file(self, id, size="40"): """ Adds a field that the user can use to upload a file. """ html="<input type='file' name='%s' size='%s'" % (id, str(size)) self.body.append(html)