diff env/lib/python3.9/site-packages/docutils/writers/s5_html/__init__.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/env/lib/python3.9/site-packages/docutils/writers/s5_html/__init__.py	Mon Mar 22 18:12:50 2021 +0000
@@ -0,0 +1,353 @@
+# $Id: __init__.py 8412 2019-11-06 18:15:21Z milde $
+# Authors: Chris Liechti <cliechti@gmx.net>;
+#          David Goodger <goodger@python.org>
+# Copyright: This module has been placed in the public domain.
+
+"""
+S5/HTML Slideshow Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import sys
+import os
+import re
+import docutils
+from docutils import frontend, nodes, utils
+from docutils.writers import html4css1
+from docutils.parsers.rst import directives
+
+themes_dir_path = utils.relative_path(
+    os.path.join(os.getcwd(), 'dummy'),
+    os.path.join(os.path.dirname(__file__), 'themes'))
+
+def find_theme(name):
+    # Where else to look for a theme?
+    # Check working dir?  Destination dir?  Config dir?  Plugins dir?
+    path = os.path.join(themes_dir_path, name)
+    if not os.path.isdir(path):
+        raise docutils.ApplicationError(
+            'Theme directory not found: %r (path: %r)' % (name, path))
+    return path
+
+
+class Writer(html4css1.Writer):
+
+    settings_spec = html4css1.Writer.settings_spec + (
+        'S5 Slideshow Specific Options',
+        'For the S5/HTML writer, the --no-toc-backlinks option '
+        '(defined in General Docutils Options above) is the default, '
+        'and should not be changed.',
+        (('Specify an installed S5 theme by name.  Overrides --theme-url.  '
+          'The default theme name is "default".  The theme files will be '
+          'copied into a "ui/<theme>" directory, in the same directory as the '
+          'destination file (output HTML).  Note that existing theme files '
+          'will not be overwritten (unless --overwrite-theme-files is used).',
+          ['--theme'],
+          {'default': 'default', 'metavar': '<name>',
+           'overrides': 'theme_url'}),
+         ('Specify an S5 theme URL.  The destination file (output HTML) will '
+          'link to this theme; nothing will be copied.  Overrides --theme.',
+          ['--theme-url'],
+          {'metavar': '<URL>', 'overrides': 'theme'}),
+         ('Allow existing theme files in the ``ui/<theme>`` directory to be '
+          'overwritten.  The default is not to overwrite theme files.',
+          ['--overwrite-theme-files'],
+          {'action': 'store_true', 'validator': frontend.validate_boolean}),
+         ('Keep existing theme files in the ``ui/<theme>`` directory; do not '
+          'overwrite any.  This is the default.',
+          ['--keep-theme-files'],
+          {'dest': 'overwrite_theme_files', 'action': 'store_false'}),
+         ('Set the initial view mode to "slideshow" [default] or "outline".',
+          ['--view-mode'],
+          {'choices': ['slideshow', 'outline'], 'default': 'slideshow',
+           'metavar': '<mode>'}),
+         ('Normally hide the presentation controls in slideshow mode. '
+          'This is the default.',
+          ['--hidden-controls'],
+          {'action': 'store_true', 'default': True,
+           'validator': frontend.validate_boolean}),
+         ('Always show the presentation controls in slideshow mode.  '
+          'The default is to hide the controls.',
+          ['--visible-controls'],
+          {'dest': 'hidden_controls', 'action': 'store_false'}),
+         ('Enable the current slide indicator ("1 / 15").  '
+          'The default is to disable it.',
+          ['--current-slide'],
+          {'action': 'store_true', 'validator': frontend.validate_boolean}),
+         ('Disable the current slide indicator.  This is the default.',
+          ['--no-current-slide'],
+          {'dest': 'current_slide', 'action': 'store_false'}),))
+
+    settings_default_overrides = {'toc_backlinks': 0}
+
+    config_section = 's5_html writer'
+    config_section_dependencies = ('writers', 'html writers',
+                                   'html4css1 writer')
+
+    def __init__(self):
+        html4css1.Writer.__init__(self)
+        self.translator_class = S5HTMLTranslator
+
+
+class S5HTMLTranslator(html4css1.HTMLTranslator):
+
+    s5_stylesheet_template = """\
+<!-- configuration parameters -->
+<meta name="defaultView" content="%(view_mode)s" />
+<meta name="controlVis" content="%(control_visibility)s" />
+<!-- style sheet links -->
+<script src="%(path)s/slides.js" type="text/javascript"></script>
+<link rel="stylesheet" href="%(path)s/slides.css"
+      type="text/css" media="projection" id="slideProj" />
+<link rel="stylesheet" href="%(path)s/outline.css"
+      type="text/css" media="screen" id="outlineStyle" />
+<link rel="stylesheet" href="%(path)s/print.css"
+      type="text/css" media="print" id="slidePrint" />
+<link rel="stylesheet" href="%(path)s/opera.css"
+      type="text/css" media="projection" id="operaFix" />\n"""
+    # The script element must go in front of the link elements to
+    # avoid a flash of unstyled content (FOUC), reproducible with
+    # Firefox.
+
+    disable_current_slide = """
+<style type="text/css">
+#currentSlide {display: none;}
+</style>\n"""
+
+    layout_template = """\
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header">
+%(header)s
+</div>
+<div id="footer">
+%(title)s%(footer)s
+</div>
+</div>\n"""
+# <div class="topleft"></div>
+# <div class="topright"></div>
+# <div class="bottomleft"></div>
+# <div class="bottomright"></div>
+
+    default_theme = 'default'
+    """Name of the default theme."""
+
+    base_theme_file = '__base__'
+    """Name of the file containing the name of the base theme."""
+
+    direct_theme_files = (
+        'slides.css', 'outline.css', 'print.css', 'opera.css', 'slides.js')
+    """Names of theme files directly linked to in the output HTML"""
+
+    indirect_theme_files = (
+        's5-core.css', 'framing.css', 'pretty.css', 'blank.gif', 'iepngfix.htc')
+    """Names of files used indirectly; imported or used by files in
+    `direct_theme_files`."""
+
+    required_theme_files = indirect_theme_files + direct_theme_files
+    """Names of mandatory theme files."""
+
+    def __init__(self, *args):
+        html4css1.HTMLTranslator.__init__(self, *args)
+        #insert S5-specific stylesheet and script stuff:
+        self.theme_file_path = None
+        self.setup_theme()
+        view_mode = self.document.settings.view_mode
+        control_visibility = ('visible', 'hidden')[self.document.settings
+                                                   .hidden_controls]
+        self.stylesheet.append(self.s5_stylesheet_template
+                               % {'path': self.theme_file_path,
+                                  'view_mode': view_mode,
+                                  'control_visibility': control_visibility})
+        if not self.document.settings.current_slide:
+            self.stylesheet.append(self.disable_current_slide)
+        self.add_meta('<meta name="version" content="S5 1.1" />\n')
+        self.s5_footer = []
+        self.s5_header = []
+        self.section_count = 0
+        self.theme_files_copied = None
+
+    def setup_theme(self):
+        if self.document.settings.theme:
+            self.copy_theme()
+        elif self.document.settings.theme_url:
+            self.theme_file_path = self.document.settings.theme_url
+        else:
+            raise docutils.ApplicationError(
+                'No theme specified for S5/HTML writer.')
+
+    def copy_theme(self):
+        """
+        Locate & copy theme files.
+
+        A theme may be explicitly based on another theme via a '__base__'
+        file.  The default base theme is 'default'.  Files are accumulated
+        from the specified theme, any base themes, and 'default'.
+        """
+        settings = self.document.settings
+        path = find_theme(settings.theme)
+        theme_paths = [path]
+        self.theme_files_copied = {}
+        required_files_copied = {}
+        # This is a link (URL) in HTML, so we use "/", not os.sep:
+        self.theme_file_path = '%s/%s' % ('ui', settings.theme)
+        if settings._destination:
+            dest = os.path.join(
+                os.path.dirname(settings._destination), 'ui', settings.theme)
+            if not os.path.isdir(dest):
+                os.makedirs(dest)
+        else:
+            # no destination, so we can't copy the theme
+            return
+        default = False
+        while path:
+            for f in os.listdir(path):  # copy all files from each theme
+                if f == self.base_theme_file:
+                    continue            # ... except the "__base__" file
+                if ( self.copy_file(f, path, dest)
+                     and f in self.required_theme_files):
+                    required_files_copied[f] = 1
+            if default:
+                break                   # "default" theme has no base theme
+            # Find the "__base__" file in theme directory:
+            base_theme_file = os.path.join(path, self.base_theme_file)
+            # If it exists, read it and record the theme path:
+            if os.path.isfile(base_theme_file):
+                with open(base_theme_file) as f:
+                    lines = f.readlines()
+                for line in lines:
+                    line = line.strip()
+                    if line and not line.startswith('#'):
+                        path = find_theme(line)
+                        if path in theme_paths: # check for duplicates (cycles)
+                            path = None         # if found, use default base
+                        else:
+                            theme_paths.append(path)
+                        break
+                else:                   # no theme name found
+                    path = None         # use default base
+            else:                       # no base theme file found
+                path = None             # use default base
+            if not path:
+                path = find_theme(self.default_theme)
+                theme_paths.append(path)
+                default = True
+        if len(required_files_copied) != len(self.required_theme_files):
+            # Some required files weren't found & couldn't be copied.
+            required = list(self.required_theme_files)
+            for f in required_files_copied.keys():
+                required.remove(f)
+            raise docutils.ApplicationError(
+                'Theme files not found: %s'
+                % ', '.join(['%r' % f for f in required]))
+
+    files_to_skip_pattern = re.compile(r'~$|\.bak$|#$|\.cvsignore$')
+
+    def copy_file(self, name, source_dir, dest_dir):
+        """
+        Copy file `name` from `source_dir` to `dest_dir`.
+        Return 1 if the file exists in either `source_dir` or `dest_dir`.
+        """
+        source = os.path.join(source_dir, name)
+        dest = os.path.join(dest_dir, name)
+        if dest in self.theme_files_copied:
+            return 1
+        else:
+            self.theme_files_copied[dest] = 1
+        if os.path.isfile(source):
+            if self.files_to_skip_pattern.search(source):
+                return None
+            settings = self.document.settings
+            if os.path.exists(dest) and not settings.overwrite_theme_files:
+                settings.record_dependencies.add(dest)
+            else:
+                src_file = open(source, 'rb')
+                src_data = src_file.read()
+                src_file.close()
+                dest_file = open(dest, 'wb')
+                dest_dir = dest_dir.replace(os.sep, '/')
+                dest_file.write(src_data.replace(b'ui/default',
+                    dest_dir[dest_dir.rfind('ui/'):].encode(
+                    sys.getfilesystemencoding())))
+                dest_file.close()
+                settings.record_dependencies.add(source)
+            return 1
+        if os.path.isfile(dest):
+            return 1
+
+    def depart_document(self, node):
+        self.head_prefix.extend([self.doctype,
+                                 self.head_prefix_template %
+                                 {'lang': self.settings.language_code}])
+        self.html_prolog.append(self.doctype)
+        self.meta.insert(0, self.content_type % self.settings.output_encoding)
+        self.head.insert(0, self.content_type % self.settings.output_encoding)
+        if self.math_header:
+            if self.math_output == 'mathjax':
+                self.head.extend(self.math_header)
+            else:
+                self.stylesheet.extend(self.math_header)
+        # skip content-type meta tag with interpolated charset value:
+        self.html_head.extend(self.head[1:])
+        self.fragment.extend(self.body)
+        # special S5 code up to the next comment line
+        header = ''.join(self.s5_header)
+        footer = ''.join(self.s5_footer)
+        title = ''.join(self.html_title).replace('<h1 class="title">', '<h1>')
+        layout = self.layout_template % {'header': header,
+                                         'title': title,
+                                         'footer': footer}
+        self.body_prefix.extend(layout)
+        self.body_prefix.append('<div class="presentation">\n')
+        self.body_prefix.append(
+            self.starttag({'classes': ['slide'], 'ids': ['slide0']}, 'div'))
+        if not self.section_count:
+            self.body.append('</div>\n')
+        #
+        self.body_suffix.insert(0, '</div>\n')
+        self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo
+                              + self.docinfo + self.body
+                              + self.body_suffix[:-1])
+
+    def depart_footer(self, node):
+        start = self.context.pop()
+        self.s5_footer.append('<h2>')
+        self.s5_footer.extend(self.body[start:])
+        self.s5_footer.append('</h2>')
+        del self.body[start:]
+
+    def depart_header(self, node):
+        start = self.context.pop()
+        header = ['<div id="header">\n']
+        header.extend(self.body[start:])
+        header.append('\n</div>\n')
+        del self.body[start:]
+        self.s5_header.extend(header)
+
+    def visit_section(self, node):
+        if not self.section_count:
+            self.body.append('\n</div>\n')
+        self.section_count += 1
+        self.section_level += 1
+        if self.section_level > 1:
+            # dummy for matching div's
+            self.body.append(self.starttag(node, 'div', CLASS='section'))
+        else:
+            self.body.append(self.starttag(node, 'div', CLASS='slide'))
+
+    def visit_subtitle(self, node):
+        if isinstance(node.parent, nodes.section):
+            level = self.section_level + self.initial_header_level - 1
+            if level == 1:
+                level = 2
+            tag = 'h%s' % level
+            self.body.append(self.starttag(node, tag, ''))
+            self.context.append('</%s>\n' % tag)
+        else:
+            html4css1.HTMLTranslator.visit_subtitle(self, node)
+
+    def visit_title(self, node):
+        html4css1.HTMLTranslator.visit_title(self, node)