master
/ .localenv / lib / python3.5 / site-packages / nbconvert / exporters / slides.py

slides.py @master raw · history · blame

"""HTML slide show Exporter class"""

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

from copy import deepcopy
from warnings import warn

from traitlets import Bool, Unicode, default

from .html import HTMLExporter

def prepare(nb):
    """Add some convenience metadata on cells for the slide template."""
    nb = deepcopy(nb)

    for cell in nb.cells:
        # Make sure every cell has a slide_type
        cell.metadata.slide_type = cell.metadata.get('slideshow', {}).get('slide_type', '-')

    # Find the first visible cell
    for index, cell in enumerate(nb.cells):
        if cell.metadata.slide_type not in {'notes', 'skip'}:
            cell.metadata.slide_type = 'slide'
            cell.metadata.slide_start = True
            cell.metadata.subslide_start = True
            first_slide_ix = index
            break
    else:
        raise ValueError("All cells are hidden, cannot create slideshow")

    in_fragment = False

    for index, cell in enumerate(nb.cells[first_slide_ix+1:],
                                 start=(first_slide_ix+1)):

        previous_cell = nb.cells[index - 1]

        # Slides are <section> elements in the HTML, subslides (the vertically
        # stacked slides) are also <section> elements inside the slides,
        # and fragments are <div>s within subslides. Subslide and fragment
        # elements can contain content:
        # <section>
        #   <section>
        #     (content)
        #     <div class="fragment">(content)</div>
        #   </section>
        # </section>

        # Get the slide type. If type is subslide or slide,
        # end the last slide/subslide/fragment as applicable.
        if cell.metadata.slide_type == 'slide':
            previous_cell.metadata.slide_end = True
            cell.metadata.slide_start = True
        if cell.metadata.slide_type in {'subslide', 'slide'}:
            previous_cell.metadata.fragment_end = in_fragment
            previous_cell.metadata.subslide_end = True
            cell.metadata.subslide_start = True
            in_fragment = False

        elif cell.metadata.slide_type == 'fragment':
            cell.metadata.fragment_start = True
            if in_fragment:
                previous_cell.metadata.fragment_end = True
            else:
                in_fragment  = True

    # The last cell will always be the end of a slide
    nb.cells[-1].metadata.fragment_end = in_fragment
    nb.cells[-1].metadata.subslide_end = True
    nb.cells[-1].metadata.slide_end = True

    return nb

class SlidesExporter(HTMLExporter):
    """Exports HTML slides with reveal.js"""

    reveal_url_prefix = Unicode(
        help="""The URL prefix for reveal.js.
        This can be a a relative URL for a local copy of reveal.js,
        or point to a CDN.

        For speaker notes to work, a local reveal.js prefix must be used.
        """
    ).tag(config=True)

    @default('reveal_url_prefix')
    def _reveal_url_prefix_default(self):
        if 'RevealHelpPreprocessor.url_prefix' in self.config:
            warn("Please update RevealHelpPreprocessor.url_prefix to "
                 "SlidesExporter.reveal_url_prefix in config files.")
            return self.config.RevealHelpPreprocessor.url_prefix
        return 'reveal.js'

    reveal_theme = Unicode('simple',
        help="""
        Name of the reveal.js theme to use.

        We look for a file with this name under `reveal_url_prefix`/css/theme/`reveal_theme`.css.

        https://github.com/hakimel/reveal.js/tree/master/css/theme has
        list of themes that ship by default with reveal.js.
        """
    ).tag(config=True)

    reveal_transition = Unicode('slide',
        help="""
        Name of the reveal.js transition to use.

        The list of transitions that ships by default with reveal.js are:
        none, fade, slide, convex, concave and zoom.
        """
    ).tag(config=True)

    reveal_scroll = Bool(False,
        help="""
        If True, enable scrolling within each slide
        """
    ).tag(config=True)

    require_js_url = Unicode(
        "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js",
        help="""
        URL to load require.js from.

        Defaults to loading from cdnjs.
        """
    ).tag(config=True)

    jquery_url = Unicode(
        "https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js",
        help="""
        URL to load jQuery from.

        Defaults to loading from cdnjs.
        """
    ).tag(config=True)

    font_awesome_url = Unicode(
        "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome.css",
        help="""
        URL to load font awesome from.

        Defaults to loading from cdnjs.
        """
    ).tag(config=True)

    @default('file_extension')
    def _file_extension_default(self):
        return '.slides.html'

    @default('template_file')
    def _template_file_default(self):
        return 'slides_reveal.tpl'

    output_mimetype = 'text/html'

    def from_notebook_node(self, nb, resources=None, **kw):
        resources = self._init_resources(resources)
        if 'reveal' not in resources:
            resources['reveal'] = {}
        resources['reveal']['url_prefix'] = self.reveal_url_prefix
        resources['reveal']['theme'] = self.reveal_theme
        resources['reveal']['transition'] = self.reveal_transition
        resources['reveal']['scroll'] = self.reveal_scroll
        resources['reveal']['require_js_url'] = self.require_js_url
        resources['reveal']['jquery_url'] = self.jquery_url
        resources['reveal']['font_awesome_url'] = self.font_awesome_url

        nb = prepare(nb)

        return super(SlidesExporter, self).from_notebook_node(nb, resources=resources, **kw)