Back to index

moin  1.9.0~rc2
html.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - HTML Widgets
00004 
00005     @copyright: 2003 Juergen Hermann <jh@web.de>
00006     @license: GNU GPL, see COPYING for details.
00007 """
00008 
00009 from MoinMoin import wikiutil
00010 
00011 # sort attributes or not? (set to 1 by unit tests)
00012 _SORT_ATTRS = 0
00013 
00014 
00015 #############################################################################
00016 ### Base Classes
00017 #############################################################################
00018 
00019 class Text:
00020     """ A text node which will be escaped.
00021     """
00022     def __init__(self, text):
00023         self.text = text
00024 
00025     def __unicode__(self):
00026         return wikiutil.escape(self.text)
00027 
00028 
00029 class Raw:
00030     """ Raw HTML code.
00031     """
00032     def __init__(self, markup):
00033         self.markup = markup
00034 
00035     def __unicode__(self):
00036         return self.markup
00037 
00038 
00039 class Element:
00040     """ Abstract base class for HTML elements.
00041     """
00042 
00043     _ATTRS = {
00044     }
00045     _DEFAULT_ATTRS = {
00046     }
00047     _BOOL_ATTRS = {
00048         'checked': None,
00049         'compact': None,
00050         'defer': None,
00051         'disabled': None,
00052         'ismap': None,
00053         'multiple': None,
00054         'nohref': None,
00055         'noshade': None,
00056         'nowrap': None,
00057         'readonly': None,
00058         'selected': None,
00059     }
00060 
00061     def __init__(self, **kw):
00062         for key in kw:
00063             key = key.lower()
00064             if key not in self._ATTRS:
00065                 raise AttributeError(
00066                     "Invalid HTML attribute %r for tag <%s>" % (
00067                         key, self.tagname()))
00068 
00069         self.attrs = self._DEFAULT_ATTRS.copy()
00070         self.attrs.update(kw)
00071 
00072     def tagname(self):
00073         return self.__class__.__name__.lower()
00074 
00075     def _openingtag(self):
00076         result = [self.tagname()]
00077         attrs = self.attrs.items()
00078         if _SORT_ATTRS:
00079             attrs.sort()
00080         for key, val in attrs:
00081             key = key.lower()
00082             if key in self._BOOL_ATTRS:
00083                 if val:
00084                     result.append(key)
00085             else:
00086                 result.append(u'%s="%s"' % (key, wikiutil.escape(val, 1)))
00087         return ' '.join(result)
00088 
00089     def __unicode__(self):
00090         raise NotImplementedError
00091 
00092 
00093 class EmptyElement(Element):
00094     """ HTML elements with an empty content model.
00095     """
00096 
00097     def __unicode__(self):
00098         return u"<%s>" % self._openingtag()
00099 
00100 
00101 class CompositeElement(Element):
00102     """ HTML elements with content.
00103     """
00104 
00105     def __init__(self, **kw):
00106         Element.__init__(self, **kw)
00107         self.children = []
00108 
00109     def append(self, child):
00110         """ Append child """
00111         self.children.append(child)
00112         return self
00113 
00114     def extend(self, children):
00115         for child in children:
00116             self.append(child)
00117         return self
00118 
00119     def __unicode__(self):
00120         childout = []
00121         for c in self.children:
00122             co = unicode(c)
00123             childout.append(co)
00124         return "<%s>%s</%s>" % (
00125             self._openingtag(),
00126             u''.join(childout),
00127             self.tagname(),
00128         )
00129 
00130 
00131 #############################################################################
00132 ### HTML Elements
00133 #############################################################################
00134 
00135 
00136 class A(CompositeElement):
00137     "anchor"
00138     _ATTRS = {
00139         'accesskey': None,
00140         'charset': None,
00141         'class': None,
00142         'coords': None,
00143         'href': None,
00144         'hreflang': None,
00145         'name': None,
00146         'onblur': None,
00147         'onfocus': None,
00148         'rel': None,
00149         'rev': None,
00150         'shape': None,
00151         'tabindex': None,
00152         'type': None,
00153     }
00154 
00155 class ABBR(CompositeElement):
00156     "abbreviated form (e.g., WWW, HTTP, etc.)"
00157     _ATTRS = {
00158         'class': None,
00159     }
00160 
00161 class ACRONYM(CompositeElement):
00162     "acronyms"
00163     _ATTRS = {
00164         'class': None,
00165     }
00166 
00167 class ADDRESS(CompositeElement):
00168     "information on author"
00169     _ATTRS = {
00170         'class': None,
00171     }
00172 
00173 class AREA(EmptyElement):
00174     "client-side image map area"
00175     _ATTRS = {
00176         'alt': None,
00177         'class': None,
00178         'href': None,
00179         'shape': None,
00180     }
00181 
00182 class B(CompositeElement):
00183     "bold text style"
00184     _ATTRS = {
00185         'class': None,
00186     }
00187 
00188 class BASE(EmptyElement):
00189     "document base URI"
00190     _ATTRS = {
00191     }
00192 
00193 class BDO(CompositeElement):
00194     "I18N BiDi over-ride"
00195     _ATTRS = {
00196         'class': None,
00197     }
00198 
00199 class BIG(CompositeElement):
00200     "large text style"
00201     _ATTRS = {
00202         'class': None,
00203     }
00204 
00205 class BLOCKQUOTE(CompositeElement):
00206     "long quotation"
00207     _ATTRS = {
00208         'class': None,
00209     }
00210 
00211 class BODY(CompositeElement):
00212     "document body"
00213     _ATTRS = {
00214         'alink': None,
00215         'background': None,
00216         'bgcolor': None,
00217         'class': None,
00218         'link': None,
00219         'onload': None,
00220         'onunload': None,
00221         'text': None,
00222         'vlink': None,
00223     }
00224 
00225 class BR(EmptyElement):
00226     "forced line break"
00227     _ATTRS = {
00228         'class': None,
00229     }
00230 
00231 class BUTTON(CompositeElement):
00232     "push button"
00233     _ATTRS = {
00234         'class': None,
00235     }
00236 
00237 class CAPTION(CompositeElement):
00238     "table caption"
00239     _ATTRS = {
00240         'class': None,
00241     }
00242 
00243 class CITE(CompositeElement):
00244     "citation"
00245     _ATTRS = {
00246         'class': None,
00247     }
00248 
00249 class CODE(CompositeElement):
00250     "computer code fragment"
00251     _ATTRS = {
00252         'class': None,
00253     }
00254 
00255 class DD(CompositeElement):
00256     "definition description"
00257     _ATTRS = {
00258         'class': None,
00259     }
00260 
00261 class DEL(CompositeElement):
00262     "deleted text"
00263     _ATTRS = {
00264         'class': None,
00265     }
00266 
00267 class DFN(CompositeElement):
00268     "instance definition"
00269     _ATTRS = {
00270         'class': None,
00271     }
00272 
00273 class DIV(CompositeElement):
00274     "generic language/style container"
00275     _ATTRS = {
00276         'id': None,
00277         'class': None,
00278     }
00279 
00280 class DL(CompositeElement):
00281     "definition list"
00282     _ATTRS = {
00283         'class': None,
00284     }
00285 
00286 class DT(CompositeElement):
00287     "definition term"
00288     _ATTRS = {
00289         'class': None,
00290     }
00291 
00292 class EM(CompositeElement):
00293     "emphasis"
00294     _ATTRS = {
00295         'class': None,
00296     }
00297 
00298 class FORM(CompositeElement):
00299     "interactive form"
00300     _ATTRS = {
00301         'accept': None,
00302         'action': None,
00303         'charset': None,
00304         'class': None,
00305         'enctype': None,
00306         'method': None,
00307         'name': None,
00308         'onreset': None,
00309         'onsubmit': None,
00310         'target': None,
00311         'id': None,
00312     }
00313     _DEFAULT_ATTRS = {
00314         'method': 'POST',
00315     }
00316 
00317 class H1(CompositeElement):
00318     "heading"
00319     _ATTRS = {
00320         'class': None,
00321     }
00322 
00323 class H2(CompositeElement):
00324     "heading"
00325     _ATTRS = {
00326         'class': None,
00327     }
00328 
00329 class H3(CompositeElement):
00330     "heading"
00331     _ATTRS = {
00332         'class': None,
00333     }
00334 
00335 class H4(CompositeElement):
00336     "heading"
00337     _ATTRS = {
00338         'class': None,
00339     }
00340 
00341 class H5(CompositeElement):
00342     "heading"
00343     _ATTRS = {
00344         'class': None,
00345     }
00346 
00347 class H6(CompositeElement):
00348     "heading"
00349     _ATTRS = {
00350         'class': None,
00351     }
00352 
00353 class HEAD(CompositeElement):
00354     "document head"
00355     _ATTRS = {
00356     }
00357 
00358 class HR(EmptyElement):
00359     "horizontal rule"
00360     _ATTRS = {
00361         'class': None,
00362     }
00363 
00364 class HTML(CompositeElement):
00365     "document root element"
00366     _ATTRS = {
00367         'version': None,
00368     }
00369 
00370 class I(CompositeElement):
00371     "italic text style"
00372     _ATTRS = {
00373         'class': None,
00374     }
00375 
00376 class IFRAME(CompositeElement):
00377     "inline subwindow"
00378     _ATTRS = {
00379         'class': None,
00380     }
00381 
00382 class IMG(EmptyElement):
00383     "embedded image"
00384     _ATTRS = {
00385         'align': None,
00386         'alt': None,
00387         'border': None,
00388         'class': None,
00389         'vspace': None,
00390     }
00391 
00392 class INPUT(EmptyElement):
00393     "form control"
00394     _ATTRS = {
00395         'accesskey': None,
00396         'align': None,
00397         'alt': None,
00398         'accept': None,
00399         'checked': None,
00400         'class': None,
00401         'disabled': None,
00402         'id': None,
00403         'ismap': None,
00404         'maxlength': None,
00405         'name': None,
00406         'onblur': None,
00407         'onchange': None,
00408         'onfocus': None,
00409         'onselect': None,
00410         'readonly': None,
00411         'size': None,
00412         'src': None,
00413         'tabindex': None,
00414         'type': None,
00415         'usemap': None,
00416         'value': None,
00417     }
00418 
00419 class INS(CompositeElement):
00420     "inserted text"
00421     _ATTRS = {
00422         'class': None,
00423     }
00424 
00425 class KBD(CompositeElement):
00426     "text to be entered by the user"
00427     _ATTRS = {
00428         'class': None,
00429     }
00430 
00431 class LABEL(CompositeElement):
00432     "form field label text"
00433     _ATTRS = {
00434         'class': None,
00435         'for_': None,
00436     }
00437 
00438     def _openingtag(self):
00439         result = [self.tagname()]
00440         attrs = self.attrs.items()
00441         if _SORT_ATTRS:
00442             attrs.sort()
00443         for key, val in attrs:
00444             key = key.lower()
00445             if key == 'for_':
00446                 key = 'for'
00447             if key in self._BOOL_ATTRS:
00448                 if val:
00449                     result.append(key)
00450             else:
00451                 result.append(u'%s="%s"' % (key, wikiutil.escape(val, 1)))
00452         return ' '.join(result)
00453 
00454 
00455 class LI(CompositeElement):
00456     "list item"
00457     _ATTRS = {
00458         'class': None,
00459     }
00460 
00461 class LINK(EmptyElement):
00462     "a media-independent link"
00463     _ATTRS = {
00464         'charset': None,
00465         'class': None,
00466         'href': None,
00467         'hreflang': None,
00468         'media': None,
00469         'rel': None,
00470         'rev': None,
00471         'target': None,
00472         'type': None,
00473     }
00474 
00475 class MAP(CompositeElement):
00476     "client-side image map"
00477     _ATTRS = {
00478         'class': None,
00479     }
00480 
00481 class META(EmptyElement):
00482     "generic metainformation"
00483     _ATTRS = {
00484     }
00485 
00486 class NOSCRIPT(CompositeElement):
00487     "alternate content container for non script-based rendering"
00488     _ATTRS = {
00489         'class': None,
00490     }
00491 
00492 class OL(CompositeElement):
00493     "ordered list"
00494     _ATTRS = {
00495         'class': None,
00496     }
00497 
00498 class OPTGROUP(CompositeElement):
00499     "option group"
00500     _ATTRS = {
00501         'class': None,
00502     }
00503 
00504 class OPTION(CompositeElement):
00505     "selectable choice"
00506     _ATTRS = {
00507         'class': None,
00508         'disabled': None,
00509         'label': None,
00510         'selected': None,
00511         'value': None,
00512     }
00513 
00514 class P(CompositeElement):
00515     "paragraph"
00516     _ATTRS = {
00517         'class': None,
00518     }
00519 
00520 class PRE(CompositeElement):
00521     "preformatted text"
00522     _ATTRS = {
00523         'class': None,
00524     }
00525 
00526 class Q(CompositeElement):
00527     "short inline quotation"
00528     _ATTRS = {
00529         'class': None,
00530     }
00531 
00532 class SAMP(CompositeElement):
00533     "sample program output, scripts, etc."
00534     _ATTRS = {
00535         'class': None,
00536     }
00537 
00538 class SCRIPT(CompositeElement):
00539     "script statements"
00540     _ATTRS = {
00541     }
00542 
00543 class SELECT(CompositeElement):
00544     "option selector"
00545     _ATTRS = {
00546         'class': None,
00547         'disabled': None,
00548         'multiple': None,
00549         'name': None,
00550         'onblur': None,
00551         'onchange': None,
00552         'onfocus': None,
00553         'size': None,
00554         'tabindex': None,
00555         'id': None,
00556     }
00557 
00558 class SMALL(CompositeElement):
00559     "small text style"
00560     _ATTRS = {
00561         'class': None,
00562     }
00563 
00564 class SPAN(CompositeElement):
00565     "generic language/style container"
00566     _ATTRS = {
00567         'class': None,
00568     }
00569 
00570 class STRONG(CompositeElement):
00571     "strong emphasis"
00572     _ATTRS = {
00573         'class': None,
00574     }
00575 
00576 class STYLE(CompositeElement):
00577     "style info"
00578     _ATTRS = {
00579     }
00580 
00581 class SUB(CompositeElement):
00582     "subscript"
00583     _ATTRS = {
00584         'class': None,
00585     }
00586 
00587 class SUP(CompositeElement):
00588     "superscript"
00589     _ATTRS = {
00590         'class': None,
00591     }
00592 
00593 class TABLE(CompositeElement):
00594     "table"
00595     _ATTRS = {
00596         'align': None,
00597         'bgcolor': None,
00598         'border': None,
00599         'cellpadding': None,
00600         'cellspacing': None,
00601         'class': None,
00602         'frame': None,
00603         'rules': None,
00604         'summary': None,
00605         'width': None,
00606     }
00607 
00608 class TBODY(CompositeElement):
00609     "table body"
00610     _ATTRS = {
00611         'align': None,
00612         'class': None,
00613     }
00614 
00615 class TD(CompositeElement):
00616     "table data cell"
00617     _ATTRS = {
00618         'abbr': None,
00619         'align': None,
00620         'class': None,
00621         'valign': None,
00622         'colspan': None,
00623         'rowspan': None,
00624     }
00625 
00626 class TEXTAREA(CompositeElement):
00627     "multi-line text field"
00628     _ATTRS = {
00629         'class': None,
00630         'cols': None,
00631         'name': None,
00632         'rows': None,
00633     }
00634 
00635 class TFOOT(CompositeElement):
00636     "table footer"
00637     _ATTRS = {
00638         'align': None,
00639         'class': None,
00640     }
00641 
00642 class TH(CompositeElement):
00643     "table header cell"
00644     _ATTRS = {
00645         'abbr': None,
00646         'align': None,
00647         'class': None,
00648     }
00649 
00650 class THEAD(CompositeElement):
00651     "table header"
00652     _ATTRS = {
00653         'align': None,
00654         'class': None,
00655     }
00656 
00657 class TITLE(CompositeElement):
00658     "document title"
00659     _ATTRS = {
00660     }
00661 
00662 class TR(CompositeElement):
00663     "table row"
00664     _ATTRS = {
00665         'align': None,
00666         'class': None,
00667     }
00668 
00669 class TT(CompositeElement):
00670     "teletype or monospaced text style"
00671     _ATTRS = {
00672         'class': None,
00673     }
00674 
00675 class UL(CompositeElement):
00676     "unordered list"
00677     _ATTRS = {
00678         'class': None,
00679     }
00680 
00681 class VAR(CompositeElement):
00682     "instance of a variable or program argument"
00683     _ATTRS = {
00684         'class': None,
00685     }
00686 
00687 
00688 #############################################################################
00689 ### Widgets
00690 #############################################################################
00691 
00692 #from MoinMoin.widget.base import Widget
00693 #class FormWidget(Widget):
00694 #    """ Widget to display data as an HTML form.
00695 #
00696 #        TODO: write code to combine the labels, data and HTML DOM to a complete form.
00697 #
00698 #        INCOMPLETE!!!
00699 #    """
00700 #
00701 #    def __init__(self, request, **kw):
00702 #        Widget.__init__(self, request)
00703 #        self.form = form(**kw)
00704 #
00705 #    def render(self):
00706 #        self.request.write(str(self.form))
00707