ext/html4zope.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # Author: David Goodger
       
     2 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     4 #
       
     5 # This file is part of CubicWeb.
       
     6 #
       
     7 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     8 # terms of the GNU Lesser General Public License as published by the Free
       
     9 # Software Foundation, either version 2.1 of the License, or (at your option)
       
    10 # any later version.
       
    11 #
       
    12 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    14 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    15 # details.
       
    16 #
       
    17 # You should have received a copy of the GNU Lesser General Public License along
       
    18 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    19 """
       
    20 
       
    21 """
       
    22 # Contact: goodger@users.sourceforge.net
       
    23 # Revision: $Revision: 1.2 $
       
    24 # Date: $Date: 2005-07-04 16:36:50 $
       
    25 # Copyright: This module has been placed in the public domain.
       
    26 
       
    27 """
       
    28 Simple HyperText Markup Language document tree Writer.
       
    29 
       
    30 The output conforms to the HTML 4.01 Transitional DTD and to the Extensible
       
    31 HTML version 1.0 Transitional DTD (*almost* strict).  The output contains a
       
    32 minimum of formatting information.  A cascading style sheet ("default.css" by
       
    33 default) is required for proper viewing with a modern graphical browser.
       
    34 
       
    35 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
       
    36 """
       
    37 
       
    38 __docformat__ = 'reStructuredText'
       
    39 
       
    40 import os
       
    41 
       
    42 from logilab.mtconverter import xml_escape
       
    43 
       
    44 from docutils import nodes
       
    45 from docutils.writers.html4css1 import Writer as CSS1Writer
       
    46 from docutils.writers.html4css1 import HTMLTranslator as CSS1HTMLTranslator
       
    47 
       
    48 default_level = int(os.environ.get('STX_DEFAULT_LEVEL', 3))
       
    49 
       
    50 class Writer(CSS1Writer):
       
    51     """css writer using our html translator"""
       
    52     def __init__(self, base_url):
       
    53         CSS1Writer.__init__(self)
       
    54         self.translator_class = URLBinder(base_url, HTMLTranslator)
       
    55 
       
    56     def apply_template(self):
       
    57         """overriding this is necessary with docutils >= 0.5"""
       
    58         return self.visitor.astext()
       
    59 
       
    60 class URLBinder:
       
    61     def __init__(self, url, klass):
       
    62         self.base_url = url
       
    63         self.translator_class = HTMLTranslator
       
    64 
       
    65     def __call__(self, document):
       
    66         translator = self.translator_class(document)
       
    67         translator.base_url = self.base_url
       
    68         return translator
       
    69 
       
    70 class HTMLTranslator(CSS1HTMLTranslator):
       
    71     """ReST tree to html translator"""
       
    72 
       
    73     def astext(self):
       
    74         """return the extracted html"""
       
    75         return ''.join(self.body)
       
    76 
       
    77     def visit_title(self, node):
       
    78         """Only 6 section levels are supported by HTML."""
       
    79         if isinstance(node.parent, nodes.topic):
       
    80             self.body.append(
       
    81                   self.starttag(node, 'p', '', CLASS='topic-title'))
       
    82             if node.parent.hasattr('id'):
       
    83                 self.body.append(
       
    84                     self.starttag({}, 'a', '', name=node.parent['id']))
       
    85                 self.context.append('</a></p>\n')
       
    86             else:
       
    87                 self.context.append('</p>\n')
       
    88         elif self.section_level == 0:
       
    89             # document title
       
    90             self.head.append('<title>%s</title>\n'
       
    91                              % self.encode(node.astext()))
       
    92             self.body.append(self.starttag(node, 'h%d' % default_level, '',
       
    93                                            CLASS='title'))
       
    94             self.context.append('</h%d>\n' % default_level)
       
    95         else:
       
    96             self.body.append(
       
    97                   self.starttag(node, 'h%s' % (
       
    98                 default_level+self.section_level-1), ''))
       
    99             atts = {}
       
   100             if node.hasattr('refid'):
       
   101                 atts['class'] = 'toc-backref'
       
   102                 atts['href'] = '%s#%s' % (self.base_url, node['refid'])
       
   103             self.body.append(self.starttag({}, 'a', '', **atts))
       
   104             self.context.append('</a></h%s>\n' % (
       
   105                 default_level+self.section_level-1))
       
   106 
       
   107     def visit_subtitle(self, node):
       
   108         """format a subtitle"""
       
   109         if isinstance(node.parent, nodes.sidebar):
       
   110             self.body.append(self.starttag(node, 'p', '',
       
   111                                            CLASS='sidebar-subtitle'))
       
   112             self.context.append('</p>\n')
       
   113         else:
       
   114             self.body.append(
       
   115                   self.starttag(node, 'h%s' % (default_level+1), '',
       
   116                                 CLASS='subtitle'))
       
   117             self.context.append('</h%s>\n' % (default_level+1))
       
   118 
       
   119     def visit_document(self, node):
       
   120         """syt: i don't want the enclosing <div class="document">"""
       
   121     def depart_document(self, node):
       
   122         """syt: i don't want the enclosing <div class="document">"""
       
   123 
       
   124     def visit_reference(self, node):
       
   125         """syt: i want absolute urls"""
       
   126         if 'refuri' in node:
       
   127             href = node['refuri']
       
   128             if ( self.settings.cloak_email_addresses
       
   129                  and href.startswith('mailto:')):
       
   130                 href = self.cloak_mailto(href)
       
   131                 self.in_mailto = 1
       
   132         else:
       
   133             assert 'refid' in node, \
       
   134                    'References must have "refuri" or "refid" attribute.'
       
   135             href = '%s#%s' % (self.base_url, node['refid'])
       
   136         atts = {'href': href, 'class': 'reference'}
       
   137         if not isinstance(node.parent, nodes.TextElement):
       
   138             assert len(node) == 1 and isinstance(node[0], nodes.image)
       
   139             atts['class'] += ' image-reference'
       
   140         self.body.append(self.starttag(node, 'a', '', **atts))
       
   141 
       
   142     ## override error messages to avoid XHTML problems ########################
       
   143     def visit_problematic(self, node):
       
   144         pass
       
   145 
       
   146     def depart_problematic(self, node):
       
   147         pass
       
   148 
       
   149     def visit_system_message(self, node):
       
   150         backref_text = ''
       
   151         if len(node['backrefs']):
       
   152             backrefs = node['backrefs']
       
   153             if len(backrefs) == 1:
       
   154                 backref_text = '; <em>backlink</em>'
       
   155             else:
       
   156                 i = 1
       
   157                 backlinks = []
       
   158                 for backref in backrefs:
       
   159                     backlinks.append(str(i))
       
   160                     i += 1
       
   161                 backref_text = ('; <em>backlinks: %s</em>'
       
   162                                 % ', '.join(backlinks))
       
   163         if node.hasattr('line'):
       
   164             line = ', line %s' % node['line']
       
   165         else:
       
   166             line = ''
       
   167         a_start = a_end = ''
       
   168         error = u'System Message: %s%s/%s%s (%s %s)%s</p>\n' % (
       
   169             a_start, node['type'], node['level'], a_end,
       
   170             self.encode(node['source']), line, backref_text)
       
   171         self.body.append(u'<div class="system-message"><b>ReST / HTML errors:</b>%s</div>' % xml_escape(error))
       
   172 
       
   173     def depart_system_message(self, node):
       
   174         pass