common/html4zope.py
changeset 1808 aa09e20dd8c0
parent 1693 49075f57cf2c
parent 1807 6d541c610165
child 1810 e95e876be17c
equal deleted inserted replaced
1693:49075f57cf2c 1808:aa09e20dd8c0
     1 # Author: David Goodger
       
     2 # Contact: goodger@users.sourceforge.net
       
     3 # Revision: $Revision: 1.2 $
       
     4 # Date: $Date: 2005-07-04 16:36:50 $
       
     5 # Copyright: This module has been placed in the public domain.
       
     6 
       
     7 """
       
     8 Simple HyperText Markup Language document tree Writer.
       
     9 
       
    10 The output conforms to the HTML 4.01 Transitional DTD and to the Extensible
       
    11 HTML version 1.0 Transitional DTD (*almost* strict).  The output contains a
       
    12 minimum of formatting information.  A cascading style sheet ("default.css" by
       
    13 default) is required for proper viewing with a modern graphical browser.
       
    14 
       
    15 http://cvs.zope.org/Zope/lib/python/docutils/writers/Attic/html4zope.py?rev=1.1.2.2&only_with_tag=ajung-restructuredtext-integration-branch&content-type=text/vnd.viewcvs-markup
       
    16 """
       
    17 
       
    18 __docformat__ = 'reStructuredText'
       
    19 
       
    20 from logilab.mtconverter import html_escape
       
    21 
       
    22 from docutils import nodes
       
    23 from docutils.writers.html4css1 import Writer as CSS1Writer
       
    24 from docutils.writers.html4css1 import HTMLTranslator as CSS1HTMLTranslator
       
    25 import os
       
    26 
       
    27 default_level = int(os.environ.get('STX_DEFAULT_LEVEL', 3))
       
    28 
       
    29 class Writer(CSS1Writer):
       
    30     """css writer using our html translator"""
       
    31     def __init__(self, base_url):
       
    32         CSS1Writer.__init__(self)
       
    33         self.translator_class = URLBinder(base_url, HTMLTranslator)
       
    34 
       
    35     def apply_template(self):
       
    36         """overriding this is necessary with docutils >= 0.5"""
       
    37         return self.visitor.astext()
       
    38 
       
    39 class URLBinder:
       
    40     def __init__(self, url, klass):
       
    41         self.base_url = url
       
    42         self.translator_class = HTMLTranslator
       
    43         
       
    44     def __call__(self, document):
       
    45         translator = self.translator_class(document)
       
    46         translator.base_url = self.base_url
       
    47         return translator
       
    48     
       
    49 class HTMLTranslator(CSS1HTMLTranslator):
       
    50     """ReST tree to html translator"""
       
    51 
       
    52     def astext(self):
       
    53         """return the extracted html"""
       
    54         return ''.join(self.body)
       
    55     
       
    56     def visit_title(self, node):
       
    57         """Only 6 section levels are supported by HTML."""
       
    58         if isinstance(node.parent, nodes.topic):
       
    59             self.body.append(
       
    60                   self.starttag(node, 'p', '', CLASS='topic-title'))
       
    61             if node.parent.hasattr('id'):
       
    62                 self.body.append(
       
    63                     self.starttag({}, 'a', '', name=node.parent['id']))
       
    64                 self.context.append('</a></p>\n')
       
    65             else:
       
    66                 self.context.append('</p>\n')
       
    67         elif self.section_level == 0:
       
    68             # document title
       
    69             self.head.append('<title>%s</title>\n'
       
    70                              % self.encode(node.astext()))
       
    71             self.body.append(self.starttag(node, 'h%d' % default_level, '',
       
    72                                            CLASS='title'))
       
    73             self.context.append('</h%d>\n' % default_level)
       
    74         else:
       
    75             self.body.append(
       
    76                   self.starttag(node, 'h%s' % (
       
    77                 default_level+self.section_level-1), ''))
       
    78             atts = {}
       
    79             if node.hasattr('refid'):
       
    80                 atts['class'] = 'toc-backref'
       
    81                 atts['href'] = '%s#%s' % (self.base_url, node['refid'])
       
    82             self.body.append(self.starttag({}, 'a', '', **atts))
       
    83             self.context.append('</a></h%s>\n' % (
       
    84                 default_level+self.section_level-1))
       
    85 
       
    86     def visit_subtitle(self, node):
       
    87         """format a subtitle"""
       
    88         if isinstance(node.parent, nodes.sidebar):
       
    89             self.body.append(self.starttag(node, 'p', '',
       
    90                                            CLASS='sidebar-subtitle'))
       
    91             self.context.append('</p>\n')
       
    92         else:
       
    93             self.body.append(
       
    94                   self.starttag(node, 'h%s' % (default_level+1), '',
       
    95                                 CLASS='subtitle'))
       
    96             self.context.append('</h%s>\n' % (default_level+1))
       
    97 
       
    98     def visit_document(self, node):
       
    99         """syt: i don't want the enclosing <div class="document">"""
       
   100     def depart_document(self, node):
       
   101         """syt: i don't want the enclosing <div class="document">"""
       
   102 
       
   103     def visit_reference(self, node):
       
   104         """syt: i want absolute urls"""
       
   105         if node.has_key('refuri'):
       
   106             href = node['refuri']
       
   107             if ( self.settings.cloak_email_addresses
       
   108                  and href.startswith('mailto:')):
       
   109                 href = self.cloak_mailto(href)
       
   110                 self.in_mailto = 1
       
   111         else:
       
   112             assert node.has_key('refid'), \
       
   113                    'References must have "refuri" or "refid" attribute.'
       
   114             href = '%s#%s' % (self.base_url, node['refid'])
       
   115         atts = {'href': href, 'class': 'reference'}
       
   116         if not isinstance(node.parent, nodes.TextElement):
       
   117             assert len(node) == 1 and isinstance(node[0], nodes.image)
       
   118             atts['class'] += ' image-reference'
       
   119         self.body.append(self.starttag(node, 'a', '', **atts))
       
   120 
       
   121     ## override error messages to avoid XHTML problems ########################
       
   122     def visit_problematic(self, node):
       
   123         pass
       
   124 
       
   125     def depart_problematic(self, node):
       
   126         pass
       
   127     
       
   128     def visit_system_message(self, node):
       
   129         backref_text = ''
       
   130         if len(node['backrefs']):
       
   131             backrefs = node['backrefs']
       
   132             if len(backrefs) == 1:
       
   133                 backref_text = '; <em>backlink</em>'
       
   134             else:
       
   135                 i = 1
       
   136                 backlinks = []
       
   137                 for backref in backrefs:
       
   138                     backlinks.append(str(i))
       
   139                     i += 1
       
   140                 backref_text = ('; <em>backlinks: %s</em>'
       
   141                                 % ', '.join(backlinks))
       
   142         if node.hasattr('line'):
       
   143             line = ', line %s' % node['line']
       
   144         else:
       
   145             line = ''
       
   146         a_start = a_end = ''
       
   147         error = u'System Message: %s%s/%s%s (%s %s)%s</p>\n' % (
       
   148             a_start, node['type'], node['level'], a_end,
       
   149             self.encode(node['source']), line, backref_text)
       
   150         self.body.append(u'<div class="system-message"><b>ReST / HTML errors:</b>%s</div>' % html_escape(error))
       
   151 
       
   152     def depart_system_message(self, node):
       
   153         pass