Django

Code

DjangoSpecifications/Docs/ConvertingRestToOtherFormats: build_htmldocs-links_work.diff

File build_htmldocs-links_work.diff, 21.2 kB (added by mrts, 2 months ago)

New patch that fixes links implemented

  • django/core/management/commands/htmldocs.py

    old new  
     1""" 
     2Command that converts Django documentation from ReST to HTML. 
     3 
     4Based on django_website/apps/docs/builder.py. 
     5""" 
     6 
     7# TODO: 
     8# 1. fix inter-page links 
     9# 2. fetch external images and place them to img directory, fix image links 
     10# 3. add images used in CSS (in notes etc) 
     11# 4. add PDF support, take inspiration from http://code.google.com/p/rst2pdf/ 
     12 
     13import os 
     14import shutil 
     15from optparse import make_option 
     16from django.core.management import BaseCommand, CommandError 
     17 
     18CSS_FILE = "docs.css" 
     19 
     20class Command(BaseCommand): 
     21    option_list = BaseCommand.option_list + ( 
     22            make_option('--single', action='store_true', dest='single', 
     23                default=False, help = "Write a single combined HTML file. " 
     24                "Not recommended, produces output that is harder to navigate."), 
     25    ) 
     26    help = ("Converts Django documentation to HTML. Uses the given Django " 
     27            "documentation directory for reading documentation source and " 
     28            "output directory for writing HTML files. Creates the output " 
     29            "directory if it does not exist.") 
     30    args = "[Django documentation directory] [output directory]" 
     31 
     32    requires_model_validation = False 
     33    can_import_settings = False 
     34 
     35    def handle(self, *paths, **options): 
     36        try: 
     37            from docutils.core import publish_parts 
     38        except ImportError: 
     39            raise CommandError("The docutils module is required to run " 
     40                    "this command.") 
     41 
     42        if len(paths) != 2: 
     43            raise CommandError("Please provide exactly two arguments in the " 
     44                    "following order: %s." % self.args) 
     45 
     46        source, dest = paths 
     47        if not os.path.exists(dest): 
     48            try: 
     49                os.mkdir(dest) 
     50            except OSError, e: 
     51                raise CommandError("Failed to create directory '%s'. " 
     52                        "The error was '%s'." % (dest, e)) 
     53        for p in source, dest: 
     54            if not os.path.isdir(p): 
     55                raise CommandError("'%s' is not a directory." % p) 
     56 
     57        css_path = os.path.join(source, "css", CSS_FILE) 
     58        if not os.path.exists(css_path): 
     59            raise CommandError("'%s' does not appear to be a Django " 
     60                    "documentation directory (stylesheet not found)" % source) 
     61        try: 
     62            shutil.copy(css_path, dest) 
     63        except IOError, e: 
     64            raise CommandError("Unable to write to directory '%s'. " 
     65                    "The error was '%s'." % (dest, e)) 
     66 
     67        opt_single = options.get("single", False) 
     68 
     69        files = [f for f in os.listdir(source) if f.endswith('.txt')] 
     70        files.sort() 
     71 
     72        if opt_single: 
     73            docs = [] 
     74        index = [] 
     75        for file in files: 
     76            out = file[:-4] + ".html" 
     77            doc = publish_parts(open(os.path.join(source, file)).read(), 
     78                    writer=get_django_html_writer(opt_single), 
     79                    settings_overrides={'initial_header_level': 2}) 
     80            try: 
     81                index.append([out, doc['title']]) 
     82            except KeyError: 
     83                index.append([out, 'UNKNOWN (%s)' % file]) 
     84         
     85            if opt_single: 
     86                doc['id'] = out 
     87                docs.append(doc) 
     88            else: 
     89                html_out = os.path.join(dest, out) 
     90                print "Writing '%s'... " % html_out, 
     91                open(html_out, 'w').write(render_doc(doc)) 
     92                print "done" 
     93         
     94        # write out either index or the single combined page 
     95        doc = None 
     96        if opt_single: 
     97            doc = { 
     98                'title' : "Documentation", 
     99                'toc' : get_single_toc(index), 
     100                'body' : get_single_body(docs) 
     101            } 
     102        else: 
     103            doc = { 
     104                'title' : "Documentation index", 
     105                'toc' : "<p>This is the automatically genrated documentation " 
     106                            "index. The automatic documentation is a basic " 
     107                            "reference, more resources are available on the " 
     108                            '<a href="http://www.djangoproject.com/documentation/">' 
     109                            "Django website</a>.</p>", 
     110                'body' : '<ul>%s</ul>' % \ 
     111                        '\n'.join(['<li><a href="%s">%s</a></li>' \ 
     112                            % (href, title) for href, title in index ]) 
     113            } 
     114        print "Writing index... ", 
     115        open(os.path.join(dest, "index.html"), 'w').write(render_doc(doc)) 
     116        print "done" 
     117        print "All done" 
     118 
     119def get_single_toc(index): 
     120    """ 
     121    Creates the table of contents for single-document output. 
     122    """ 
     123    toc = '<ul class="toc">%s</ul>' 
     124    line = '<li><a class="reference internal" href="#%s">%s</a></li>' 
     125    return toc % '\n'.join([ line % (name, title) for name, title in index]) 
     126     
     127def get_single_body(docs): 
     128    """ 
     129    Joins individual documents into a single document. 
     130    """ 
     131    chunk = '<h1 id="%(id)s">%(title)s</h1>\n%(body)s' 
     132    return '\n'.join([chunk % doc for doc in docs]) 
     133 
     134def render_doc(doc): 
     135    """ 
     136    Renders the document with a HTML template. 
     137    """ 
     138    return ("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     139        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
     140<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
     141        <head> 
     142                <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 
     143                <meta http-equiv="Content-Language" content="en-us" /> 
     144                <title>%(title)s | Django Documentation</title> 
     145                <link href="docs.css" rel="stylesheet" type="text/css" media="screen" /> 
     146    </head> 
     147    <body id="documentation" class="default"> 
     148    <div id="container"> 
     149        <div id="header"> 
     150            <ul id="nav-global"> 
     151                <li id="nav-homepage"><a href="index.html">Documentation index</a></li> 
     152            </ul> 
     153        </div> 
     154        <div id="billboard"><h2><a href="index.html" style="color: white; height:40px; padding-top:20px; text-indent:22px;">Django documentation</a></h2></div> 
     155        <div id="columnwrap"> 
     156            <div id="content-main"> 
     157                <h1>%(title)s</h1> 
     158                %(body)s 
     159            </div> 
     160            <div id="content-related" class="sidebar"> 
     161                <h2>Contents</h2> 
     162                %(toc)s 
     163            </div> 
     164        </div> 
     165        <div id="footer"> 
     166            <p><a href="index.html"><< Back to documentation index</a></p> 
     167        </div> 
     168    </div> 
     169    </body> 
     170</html>""" % doc).encode('utf-8') 
     171 
     172def get_django_html_writer(is_single): 
     173    """ 
     174    Returns the Django HTML writer instance. Note that we need to define the 
     175    classes inside a function to avoid triggering an import error when 
     176    docutils is unavailable. 
     177    """ 
     178    from docutils import nodes 
     179    from docutils.writers import html4css1 
     180    import re 
     181 
     182    class DjangoHTMLTranslator(html4css1.HTMLTranslator): 
     183        """ 
     184        reST -> HTML translator subclass that outputs Django-specific markup. 
     185        """ 
     186         
     187        # Prevent name attributes from being generated 
     188        named_tags = [] 
     189         
     190        def __init__(self, document): 
     191            html4css1.HTMLTranslator.__init__(self, document) 
     192            self._in_literal = 0 
     193         
     194        # Remove the default border=1 from <table> 
     195        def visit_table(self, node): 
     196            self.body.append(self.starttag(node, 'table', CLASS='docutils')) 
     197 
     198        # No smartypants conversion 
     199 
     200        # Avoid <blockquote>s around merely indented nodes. 
     201        # Adapted from 
     202        # http://thread.gmane.org/gmane.text.docutils.user/742/focus=804 
     203         
     204        _suppress_blockquote_child_nodes = ( 
     205            nodes.bullet_list, nodes.enumerated_list, nodes.definition_list, 
     206            nodes.literal_block, nodes.doctest_block, nodes.line_block, 
     207            nodes.table 
     208        ) 
     209        def _bq_is_valid(self, node): 
     210            return len(node.children) != 1 \ 
     211                    or not isinstance(node.children[0], 
     212                            self._suppress_blockquote_child_nodes) 
     213                                             
     214        def visit_block_quote(self, node): 
     215            if self._bq_is_valid(node): 
     216                html4css1.HTMLTranslator.visit_block_quote(self, node) 
     217 
     218        def depart_block_quote(self, node): 
     219            if self._bq_is_valid(node): 
     220                html4css1.HTMLTranslator.depart_block_quote(self, node) 
     221 
     222    # Fix inter-page links 
     223 
     224    class MultiPageTranslator(DjangoHTMLTranslator): 
     225        def visit_reference(self, node, regex=re.compile(r'^../([-\w]+)/')): 
     226            if node.has_key('refuri') and regex.match(node['refuri']): 
     227                node['refuri'] = regex.sub(r'\1.html', node['refuri']) 
     228            html4css1.HTMLTranslator.visit_reference(self, node) 
     229 
     230    class SinglePageTranslator(DjangoHTMLTranslator): 
     231        # Destroys ../foo/#bar style anchors (replacing them with #foo), 
     232        # but we can live with that 
     233        def visit_reference(self, node, regex=re.compile(r'^../([-\w]+)/.*')): 
     234            if node.has_key('refuri') and regex.match(node['refuri']): 
     235                node['refuri'] = regex.sub(r'#\1.html', node['refuri']) 
     236            html4css1.HTMLTranslator.visit_reference(self, node) 
     237 
     238    class DjangoHTMLWriter(html4css1.Writer): 
     239        """ 
     240        HTML writer that adds a "toc" key to the set of doc parts. 
     241        """ 
     242        def __init__(self): 
     243            html4css1.Writer.__init__(self) 
     244            if is_single: 
     245                self.translator_class = SinglePageTranslator 
     246            else: 
     247                self.translator_class = MultiPageTranslator 
     248 
     249        def translate(self): 
     250            # build the document 
     251            html4css1.Writer.translate(self) 
     252 
     253            # build the contents 
     254            contents = self.build_contents(self.document) 
     255            contents_doc = self.document.copy() 
     256            contents_doc.children = contents 
     257            contents_visitor = self.translator_class(contents_doc) 
     258            contents_doc.walkabout(contents_visitor) 
     259            self.parts['toc'] = "<ul class='toc'>%s</ul>" \ 
     260                    % ''.join(contents_visitor.fragment) 
     261 
     262        def build_contents(self, node, level=0): 
     263            level += 1 
     264            sections = [] 
     265            i = len(node) - 1 
     266            while i >= 0 and isinstance(node[i], nodes.section): 
     267                sections.append(node[i]) 
     268                i -= 1 
     269            sections.reverse() 
     270            entries = [] 
     271            autonum = 0 
     272            depth = 4   # XXX FIXME 
     273            for section in sections: 
     274                title = section[0] 
     275                entrytext = title 
     276                try: 
     277                    reference = nodes.reference('', '', 
     278                            refid=section['ids'][0], *entrytext) 
     279                except IndexError: 
     280                    continue 
     281                ref_id = self.document.set_id(reference) 
     282                entry = nodes.paragraph('', '', reference) 
     283                item = nodes.list_item('', entry) 
     284                if level < depth: 
     285                    subsects = self.build_contents(section, level) 
     286                    item += subsects 
     287                entries.append(item) 
     288            if entries: 
     289                contents = nodes.bullet_list('', *entries) 
     290                return contents 
     291            else: 
     292                return [] 
     293 
     294    return DjangoHTMLWriter() 
  • docs/css/docs.css

    old new  
     1/*  
     2djangoproject.com by Wilson Miner (wilson@lawrence.com) 
     3Copyright (c) 2005 Lawrence Journal-World. Please don't steal. 
     4*/ 
     5 
     6 
     7/* SETUP */ 
     8 
     9body { margin:0; padding:0; background:#092e20; color:white; } 
     10body, th, td { font:12px/1.4em Verdana,sans-serif; } 
     11#container { position:relative; min-width:55em; max-width:100em; } 
     12#homepage #container { max-width:100em; } 
     13 
     14/* LINKS */ 
     15 
     16a {text-decoration: none;} 
     17a img {border: none;} 
     18a:link, a:visited { color:#ffc757; } 
     19#content-main a:link, #content-main a:visited { color:#ab5603; text-decoration:underline; } 
     20#content-secondary a:link, #content-secondary a:visited { color:#ffc757; text-decoration:none; } 
     21a:hover { color:#ffe761; } 
     22#content-main a:hover { background-color:#E0FFB8; color:#234f32; text-decoration:none; } 
     23#content-secondary a:hover { color:#ffe761; background:none; } 
     24#content-main h2 a, #content-main h3 a { text-decoration:none !important; } 
     25 
     26/* HEADER */ 
     27 
     28#header { position:relative; height:6.5em; background:#092e20; } 
     29#header h1#logo { margin:0; width:111px; height:41px; position:absolute; bottom:10px; left:25px; } 
     30 
     31/* NAV */ 
     32 
     33#nav-global { position:absolute; margin:0; bottom:0; right:0; font-family:"Trebuchet MS",sans-serif; white-space:nowrap; } 
     34#nav-global li { display:block; float:left; list-style-type:none; margin:0; padding:0; } 
     35#nav-global a { display:block; float:left; padding:5em 16px 10px 16px; background:#092e20; } 
     36#nav-global a:hover { color:white; background:#234f32; } 
     37#homepage #nav-homepage a, #overview #nav-overview a, #download #nav-download a, #documentation #nav-documentation a, #weblog #nav-weblog a, #community #nav-community a, #blogroll #nav-blogroll a, #code #nav-code a { color:white; background:#092e20 url(../img/site/nav_bg.gif) bottom repeat-x; } 
     38 
     39/* COLUMNS */ 
     40 
     41#columnwrap { background:#234f32; padding-bottom:10px; } 
     42#subwrap { background:#326342; width:73%; float:left; padding-bottom:10px; } 
     43#content-main { float:left; width:70%; background:white; color:black; padding-bottom:10px; } 
     44#generic #content-main, #code #content-main { width:100%; } 
     45#content-main * { margin-left:22px; margin-right:24px; } 
     46#content-main * * { margin-left:0; margin-right:0; } 
     47.sidebar { font-size:92%; } 
     48.sidebar * { margin-left:14px; margin-right:14px; } 
     49.sidebar * * { margin-left:0; margin-right:0; } 
     50#content-extra { float:right; width:27%; } 
     51#content-related { float:right; width:30%;} 
     52#content-secondary { clear:both; background:#487858; margin-left:0; margin-right:0; margin-top:15px; margin-bottom:-10px; padding:10px 24px; color:white; } 
     53.subcol-primary, .subcol-secondary { width:40%; float:left; padding-bottom:1.2em; } 
     54.subcol-primary { margin-right:1%; } 
     55 
     56/* CONTENT */ 
     57 
     58h1,h2,h3 { margin-top:.8em; font-family:"Trebuchet MS",sans-serif; font-weight:normal; } 
     59h1 { font-size:218%; margin-top:.6em; margin-bottom:.6em; color:#092e20; line-height:1.1em; } 
     60h2 { font-size:150%; margin-top:1em; margin-bottom:.2em; line-height:1.2em; color:#092e20; } 
     61#homepage h2 { font-size:140%; } 
     62h3 { font-size:125%; font-weight:bold; margin-bottom:.2em; color:#487858; } 
     63h4 { font-size:100%; font-weight:bold; margin-bottom:-3px; margin-top:1.2em; text-transform:uppercase; letter-spacing:1px; } 
     64h4 pre, h4 tt, h4 .literal { text-transform:none; } 
     65h5 { font-size:1em; font-weight:bold; margin-top:1.5em; margin-bottom:3px; } 
     66p, ul, dl { margin-top:.6em; margin-bottom:.8em; } 
     67hr { color:#ccc; background-color:#ccc; height:1px; border:0; } 
     68p.date { color:#487858; margin-top:-.2em; } 
     69p.more { margin-top:-.4em; } 
     70.sidebar p.date { color:#90ba9e; } 
     71#content-secondary h2, .sidebar h2 { color:white; } 
     72#content-secondary h3, .sidebar h3 { color:#9aef3f; } 
     73#content-secondary h2:first-child { margin-top:.6em; } 
     74.sidebar h2:first-child { margin-top:.8em; } 
     75#content-main h2, #content-main h3 { margin-top:1.2em; } 
     76h2.deck { margin-top:-.5em !important; margin-bottom:.6em; color:#487858; } 
     77ins { text-decoration: none; } 
     78ins a { text-decoration: none; } 
     79 
     80/* LISTS */ 
     81 
     82ul { padding-left:2em; } 
     83ol { padding-left:30px; } 
     84ul li { list-style-type:square; margin-bottom:.4em; } 
     85ul ul { padding-left:1.2em; } 
     86ul ul ul { padding-left:1em; } 
     87ul.linklist, ul.toc { padding-left:0; } 
     88ul.toc ul { margin-left:.6em; } 
     89ul.toc ul li { list-style-type:square; } 
     90ul.toc ul ul li { list-style-type:disc; } 
     91ul.linklist li, ul.toc li { list-style-type:none; } 
     92dt { font-weight:bold; margin-top:.5em; font-size:1.1em; } 
     93dd { margin-bottom:.8em; } 
     94 
     95/*  RSS  */ 
     96 
     97a.rss { font:bold 10px Verdana, sans-serif; padding:0 .2em; border: 1px solid; text-decoration:none; background:#f60;color: #fff; border-color:#ffc8a4 #7d3302 #3f1a01 #ff9a57; margin:0 3px; vertical-align:middle; } 
     98#content-main a.rss { color:#fff; text-decoration:none; } 
     99a.rss:hover, a.rss:link, a.rss:visited { color:#fff; text-decoration:none; } 
     100 
     101/* BLOCKQUOTES */ 
     102 
     103#weblog blockquote { padding-left:0.8em; padding-right:1em; font:125%/1.2em "Trebuchet MS", sans-serif; color:#234f32; border-left:2px solid #94da3a; } 
     104.sidebar blockquote { margin-top:1.5em; margin-bottom:1.5em; } 
     105.sidebar blockquote p { font:italic 175%/1.2em "Trebuchet MS",sans-serif; color:#94da3a; } 
     106.sidebar blockquote cite { display:block; font-style:normal; line-height:1.2em; margin-top:-.8em; color:#94da3a; } 
     107.sidebar cite strong { font-weight:normal; color:white; } 
     108 
     109/* CODE BLOCKS */ 
     110 
     111.literal { white-space:nowrap; } 
     112.literal, .literal-block { color:#234f32; } 
     113.sidebar .literal { color:white; background:transparent; font-size:11px; } 
     114pre, .literal-block { font-size:medium; background:#E0FFB8; border:1px solid #94da3a; border-width:1px 0; margin: 1em 0; padding: .3em .4em; overflow: auto; } 
     115dt .literal, table .literal { background:none; } 
     116textarea.codedump { font-size:10px; color:#234f32; width:100%; background:#E0FFB8; border:1px solid #94da3a; border-width:1px 0; padding: .3em .4em; } 
     117 
     118/* NOTES & ADMONITIONS */ 
     119 
     120.note, .admonition, .caution { padding:.8em 1em .8em; margin: 1em 0; border:1px solid #94da3a; } 
     121.admonition-title { font-weight:bold; margin-top:0 !important; margin-bottom:0 !important;} 
     122.admonition .last { margin-bottom:0 !important; } 
     123.admonition-philosophy { padding-left:65px; background:url(../img/doc/icons/docicons-philosophy.gif) .8em .8em no-repeat;} 
     124.admonition-note, .caution { padding-left:65px; background:url(../img/doc/icons/docicons-note.gif) .8em .8em no-repeat;} 
     125.admonition-behind-the-scenes { padding-left:65px; background:url(../img/doc/icons/docicons-behindscenes.gif) .8em .8em no-repeat;} 
     126 
     127/* DOCS */ 
     128 
     129#documentation h2, #documentation h3, #documentation h4 { margin-top:1.4em; } 
     130#documentation dd { margin-left:1em; } 
     131#content-main table { color:#000; } 
     132table.docutils { border-collapse:collapse; } 
     133table.docutils thead th { border-bottom:2px solid #dfdfdf; text-align:left; } 
     134table.docutils td, table.docutils th { border-bottom:1px solid #dfdfdf; padding:4px 2px;} 
     135table.docutils td p { margin-top:0; margin-bottom:.5em; } 
     136#documentation #content-related .literal { background:transparent !important; } 
     137 
     138/* BILLBOARDS */ 
     139 
     140#billboard { background:#94da3a url(../img/site/bbdsm_bg.gif) repeat-x; border-bottom:6px solid #092e20; } 
     141#billboard h2 { margin:0; } 
     142#generic #billboard { display:none; } 
     143#homepage #billboard { background-image: url(../img/site/bbd_bg.gif); } 
     144#homepage #billboard h2 { margin:0; text-indent:-5000px; height:80px; width:633px; background:url(../img/site/bbd_homepage.gif) no-repeat; } 
     145#overview #billboard h2 { margin:0; text-indent:-5000px; height:60px; width:203px; background:url(../img/site/bbd_overview.gif) no-repeat; } 
     146#download #billboard h2 { margin:0; text-indent:-5000px; height:60px; width:203px; background:url(../img/site/bbd_download.gif) no-repeat; } 
     147#documentation #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_documentation.gif) no-repeat; } 
     148#weblog #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_weblog.gif) no-repeat; } 
     149#community #billboard h2 { display:block; margin:0; text-indent:-5000px; height:60px; width:226px; background:url(../img/site/bbd_community.gif) no-repeat; } 
     150#blogroll #billboard h2 { display:block; margin:0; text-indent:-5000px; height:60px; width:168px; background:url(../img/site/bbd_blogroll.gif) no-repeat; } 
     151#code #billboard h2 a { display:block; margin:0; text-indent:-5000px; height:60px; width:184px; background:url(../img/site/bbd_code.gif) no-repeat; } 
     152 
     153/* FOOTER */ 
     154 
     155#footer { clear:both; color:#487858; padding:10px 20px; font-size:90%; } 
     156 
     157/* COMMENTS */ 
     158 
     159.comment { margin:15px 0; } 
     160div.comment p { margin-left:1em; } 
     161#weblog div.comment p.date { margin-bottom:.2em; color:#94da3a; } 
     162 
     163/* MISC */ 
     164 
     165.small { font-size:90%; } 
     166h3 .small { font-size:80%; } 
     167.quiet { font-weight:normal; } 
     168.clear { clear:both; } 
     169#content-main .quiet { color:#487858; } 
     170#content-secondary .quiet { color:#90ba9e; } 
     171 
     172/*  CLEARFIX KLUDGE */ 
     173 
     174#columnwrap:after { 
     175    content: ".";  
     176    display: block;  
     177    height: 0;  
     178    clear: both;  
     179    visibility: hidden; 
     180} 
     181#columnwrap { display: inline-block; } 
     182 
     183/* Hides from IE-mac \*/ 
     184* html #columnwrap { height: 1%; } 
     185#columnwrap { display: block; } 
     186/* End hide from IE-mac */ 
     187 
     188#subwrap:after { 
     189    content: ".";  
     190    display: block;  
     191    height: 0;  
     192    clear: both;  
     193    visibility: hidden; 
     194} 
     195#subwrap { display: inline-block; } 
     196 
     197/* Hides from IE-mac \*/ 
     198* html #subwrap { height: 1%; } 
     199#subwrap { display: block; } 
     200/* End hide from IE-mac */om IE-mac */