diff --git a/.gitignore b/.gitignore index 789619f..f33f4b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.pyc +.DS_Store + .installed.cfg bin @@ -20,3 +22,9 @@ _build /.tox/ .sass-cache /pip-selfcheck.json + +# used by GAM, for debugging/tracing +/src/hieroglyph/hack.py + +BuroLa +src/TDD_testslides/__Result/ diff --git a/docs/Makefile b/docs/Makefile index 4eeddc4..ba69a45 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = ../bin/sphinx-build +SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build diff --git a/docs/conf.py b/docs/conf.py index 9d68209..178a053 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,8 +41,8 @@ 'hieroglyph', ] -if not on_rtd: - extensions.append('sphinxcontrib.googleanalytics') +#GAM#if not on_rtd: +#GAM# extensions.append('sphinxcontrib.googleanalytics') # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/gio_slides.rst b/docs/gio_slides.rst new file mode 100644 index 0000000..2916c40 --- /dev/null +++ b/docs/gio_slides.rst @@ -0,0 +1,66 @@ +================ +Google IO slides +================ + +The theme ``slides2`` enables a modern slidedeck, based on the one Google introduced for I/O 2012; +and still updates. It has support for mobile/touch devices too. But it not fully compatible with +the (original) `slides` and `single-level` themas. + +Currently the options are partly described in the :ref:`original documentation +` and partly here. This page is work in progress (as is the code support). + +Presenting +********** + +For *presenter-mode*, **start** the page with the suffix `?presentme=true`; use an URL without +page-suffix (#). The keyboard option 'c' does not (yet) work. In this mode, two windows are +shown, typically on 2 (physical) screens: a normal one for the audience, and one with more info for +the presenter. + +Note: presenter-mode and presentation-links don't work correctly. Links are (only) clickable in the +'audience' window; they open the presentation in a new tab/window, bu no presenter-window will +pop-up! + +Keyboard control +================= + +.. note:: The action-keys are hardcodes in ``js/slide-deck.js`` + (function: :js:func:`SlideDeck.prototype.onBodyKeyDown_` ) + +Navigation +---------- + +============ =================================== =============== +*Action* *Keys* *Remarks* +------------ ----------------------------------- --------------- +**Next** RightArrow, Space, PgDn, DownArrow GoTo next slide +**Back** LeftArrow, Backspace, PgUp, UpArrow +============ =================================== =============== + + + +Toggles +------- + +============ ======================== ======================================================== +*Key* *Action* *Remarks* +------------ ------------------------ -------------------------------------------------------- +**w** wide/narrow-screen change width of the slide, dynamically +**o** overview mode Show all slides as miniatures +** overview mode Displays the 'overview'-class, when available +**p** show speaker notes if they're on the current slide +**f** fullscreen viewing when browser supports it; not on Safari) +**h** code highlighting XXX +============ ======================== ======================================================== + +Keys are not case-sensitive. Most options can be toggled 'off' with **ESC** (has no effect on wide/narrow). + +NOTES +***** + +* Each slidedeck (file) will automatically become a title- and end-slide. Both will have an icon, + that should be named ``title_icon.png`` and ``end_icon.png`` and should be places in the + ``_static/slides2/`` directory. Those images will be (css) scaled, to 128*128 pixels (by default; + this can be changed in CSS XXX). +* Do **NOT** add a newline (`\n`) in the title (version/releases string). It will break the slides; + and shows *noting* diff --git a/docs/index.rst b/docs/index.rst index 571cb2e..1ea98c2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,6 +32,7 @@ Hieroglyph is an extension for `Sphinx`_ which builds HTML slides from getting-started styling themes + gio_slides advanced config theme-creation @@ -72,6 +73,7 @@ Related Projects getting-started styling themes + gio_slides advanced config theme-creation diff --git a/docs/themes.rst b/docs/themes.rst index 725303b..1419753 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -57,11 +57,13 @@ Hieroglyph includes some classes that for styling slides: from the right to left. +.. _org_doc_gio_slides: + Slides2 ======= The ``slides2`` theme was added in Hieroglyph 0.7, and as based on the -`Google I/O 2012+`_ HTML slide templates. +`Google I/O 2012+`_ HTML slide templates. Also see: :doc:`gio_slides` Theme Options ------------- diff --git a/setup.cfg b/setup.cfg index e7235a5..2aa289b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [egg_info] -tag_build = .dev +tag_build = .dev.GAM [bdist_wheel] universal = 1 diff --git a/src/TDD_testslides/IN/all.rst b/src/TDD_testslides/IN/all.rst new file mode 100644 index 0000000..4c30456 --- /dev/null +++ b/src/TDD_testslides/IN/all.rst @@ -0,0 +1,140 @@ +=== +All +=== + +Note: For this demo the conf should contain `slide_levels = 2` + +H2-1 This will become a the first h1 +==================================== + +on a new slide + +H2-2 This should be a new slide, again with a h2 header +======================================================= + +The H2-2 line is missing! + +H3 But this H3 is shown instead +------------------------------- + +There should be a (h3) header above this line + + +H2-3 Again +========== + +A new side + +H2-4 More missing lines +======================= + +The lines H2-4 and H3-1 will be gone ... + +H3-1 First h3 +------------- + +This is shown (but not H3-1) + +H3-2 Second h3 +-------------- + +This is shown (as well as H3-2, as slide title) + + + +H2-5 Now with h2+3+4 +==================== + +Reset again (new H2 slide) + +H2-6 Demo +========= + +Echo: H2-6 Demo + +H3 A h2 with an h4 +------------------ + +Echo: H3 A h2 with an h4 + +H4 What does happen? +^^^^^^^^^^^^^^^^^^^^ + +Echo: H4 What does happen? + + +H2-7 slide +========== + +Echo H2-7 slide + +.. slide:: Title + + Some body + +.. slide:: another slide + + With a title + +.. slide:: + + Thise `slide` slide has no title + +H2-8 nextslide +============== + +echo H2-8 nextslide + +.. nextslide:: + :increment: + +echo nextslide (without title, increment) + +.. nextslide:: next + +echo nextslide (with title: next) + + + + +.. ifslides:: + ..nextslide:: Title + + echo DOT DOT slide COLON COLON Title + + +.. slide:: another slide + + echo DOT DOT slide COLON COLON another slide + +.. slide:: + + echo DOT DOT slide + + Thise `slide` slide has no title + +H2 nextslide +============ + +echo H2 nextslide + +.. nextslide:: + :increment: + +echo DOT DOT nextslide +Text on **nextslide** + + + + + + +OLD +=== +.. notslides:: + + oud + +.. slides:: + + oud diff --git a/src/TDD_testslides/IN/index.rst b/src/TDD_testslides/IN/index.rst new file mode 100644 index 0000000..f44d2e5 --- /dev/null +++ b/src/TDD_testslides/IN/index.rst @@ -0,0 +1,10 @@ +============== +Hplus Bug Demo +============== + +.. toctree:: + + mini + next.slide + all + levels diff --git a/src/TDD_testslides/IN/levels.rst b/src/TDD_testslides/IN/levels.rst new file mode 100644 index 0000000..2df39fe --- /dev/null +++ b/src/TDD_testslides/IN/levels.rst @@ -0,0 +1,63 @@ +###### +LEVELS +###### + +- ## with overline, for books (titles) +- ** with overline, for parts +- #, for chapters +- \*, for sections +- =, for subsections +- -, for sub-subsections +- ^, for paragraphs +- ", SPARE + +## +H1 +## + +Books + +** +H2 +** + +Parts + +H3 +## + +Chapters + +H4 +** + +Sections + +H5 +== + +Subsections + +H6 +-- + +Sub-subsections + +H7 +^^ + +Paragraphs + +H8 +"" + +spare + +######### +H1, Again +######### + +.. nextslide:: + :increment: + +Curious about slide-level and H level diff --git a/src/TDD_testslides/IN/mini.rst b/src/TDD_testslides/IN/mini.rst new file mode 100644 index 0000000..5d3e4fe --- /dev/null +++ b/src/TDD_testslides/IN/mini.rst @@ -0,0 +1,17 @@ +==== +Mini +==== + +AutoSlide +========= + +Use only as sub-header, not as nextslide header +----------------------------------------------- + +echo h3 + +.. nextslide:: + :increment: + +This should be on a new slide, named `AutoSlide (2)`, not of the last h3 + diff --git a/src/TDD_testslides/IN/next.slide.rst b/src/TDD_testslides/IN/next.slide.rst new file mode 100644 index 0000000..90af217 --- /dev/null +++ b/src/TDD_testslides/IN/next.slide.rst @@ -0,0 +1,123 @@ +================= +Slide & nextslide +================= + +Some text + +REF +==== + +.. nextslide:: DEMO + +qaz + +slide +===== + +(empty) + +.. slide:: SlideTitle + + slide with title + +.. slide:: Always + :inline-contents: True + + slide (inline-contents) + +.. slide:: + + slide (without a title) + +BUG +==== + +.. slide:: Slide-slide + + note, there is a line after this slide + +This line is lost (BUG) + + +NextSlides +========== + +echo NextSlides + +.. nextslide:: + :increment: + +echo nextslide, increment + +NextSlides H3 +============= + +H3 +-- + +echo h3 + +.. nextslide:: + :increment: + +This should be on a new slide, named `NextSlides H3 (2)` + + +Slide+next +========== + +.. slide:: new + + echo slide:: new + +.. nextslide:: + :increment: + +echo nextslide:: (increment) + +.. nextslide:: + :increment: + +echo nextslide:: (increment) + +Nested +------- + +.. slide:: new + + echo slide:: new + + .. nextslide:: + :increment: + + echo nextslide:: (increment) + + .. nextslide:: + :increment: + + echo nextslide:: (increment) + +Nextslide with auto +=================== + +still with BUG! + +Before nextslide +---------------- + +.. nextslide:: + :increment + +After nextslide +--------------- + +This should be a new slide! + +With title `Nextslide with auto (2)` and a header `After nextslide` + + +END +=== + +That is all folks + diff --git a/src/TDD_testslides/Makefile b/src/TDD_testslides/Makefile new file mode 100644 index 0000000..ad3cecf --- /dev/null +++ b/src/TDD_testslides/Makefile @@ -0,0 +1,23 @@ +default: slides + + +ifdef VIRTUAL_ENV + TOOL_VER:=$(notdir ${VIRTUAL_ENV}) +else + TOOL_VER=_base_ +endif + +OUTd = __Result/${TOOL_VER}/ + + +slides html : + sphinx-build -Ea -b $@ -c. IN ${OUTd}$@/ + +clean: + rm -rf ${OUTd} + +veryclean: clean + rm -f *-DUMP.xml + rm -rf __Result/ + + diff --git a/src/TDD_testslides/conf.py b/src/TDD_testslides/conf.py new file mode 100644 index 0000000..2ca646d --- /dev/null +++ b/src/TDD_testslides/conf.py @@ -0,0 +1,35 @@ +# General information about the project. +project = 'Bug Demo' +copyright = '2015, ALbert Mietus: Use at will' +author = 'ALbert Mietus' + +source_suffix = '.rst' +master_doc = 'index' + +slide_levels = 2 ## RELEVANT FOR BUG +slide_link_to_html=True +slide_link_html_to_slides=True + + +# -- Options for HTML output ---------------------------------------------- +html_theme = 'default' + +# -- Hieroglyph Slide Configuration ------------ +extensions = [ 'hieroglyph',] + +slide_title = 'TDD fixed bugs' + +### +### Choose one of (try all combinations) +### + +slide_theme = 'slides' +#slide_theme = 'single-level' +#slide_theme = 'slides2' + +autoslides = True +#autoslides = False + + + + diff --git a/src/hieroglyph/__init__.py b/src/hieroglyph/__init__.py index 1aa5e76..3e2aaff 100644 --- a/src/hieroglyph/__init__.py +++ b/src/hieroglyph/__init__.py @@ -74,3 +74,4 @@ def setup(app): app.connect('builder-inited', html.inspect_config) app.connect('html-page-context', html.add_link) + diff --git a/src/hieroglyph/directives.py b/src/hieroglyph/directives.py index 24e64e2..ab332e4 100644 --- a/src/hieroglyph/directives.py +++ b/src/hieroglyph/directives.py @@ -1,16 +1,15 @@ + from docutils import nodes from sphinx.util.nodes import set_source_info from docutils.nodes import SkipNode from docutils.parsers.rst import Directive, directives -from docutils.parsers.rst.directives import ( - admonitions, -) +from docutils.parsers.rst.directives import admonitions from docutils.parsers.rst.roles import set_classes from docutils.transforms import Transform -def raiseSkip(self, node): +def raiseSkip(self, node): # Used in __init__: app.add_node raise SkipNode() @@ -27,25 +26,17 @@ class IfBuildingSlides(Directive): option_spec = {} def run(self): - if self.name in ('slides', 'notslides',): + if self.name in ('slides', 'notslides',): # these are deprecated, print a warning import warnings - - # these are deprecated, print a warning - warnings.warn( - "The %s directive has been deprecated; replace with if%s" % ( - self.name, self.name, - ), - stacklevel=2, - ) + warnings.warn("The %s directive has been deprecated; replace with if%s" % (self.name, self.name)) node = if_slides() node.document = self.state.document set_source_info(self, node) - node.attributes['ifslides'] = self.name in ('slides', 'ifslides',) + node.attributes['ifslides'] = self.name in ('slides', 'ifslides') - self.state.nested_parse(self.content, self.content_offset, - node, match_titles=1) + self.state.nested_parse(self.content, self.content_offset, node, match_titles=1) return [node] @@ -111,20 +102,15 @@ class TransformNextSlides(Transform): def apply(self, *args, **kwargs): - app = self.document.settings.env.app - from hieroglyph import builder + app = self.document.settings.env.app is_slides = builder.building_slides(app) - return self.apply_to_document( - self.document, - env=self.document.settings.env, - building_slides=is_slides, - ) + self.apply_to_document(self.document, env=self.document.settings.env, building_slides=is_slides) - def apply_to_document(self, document, env, building_slides): + def apply_to_document(self, document, env, building_slides): need_reread = False for node in document.traverse(nextslide): @@ -134,66 +120,70 @@ def apply_to_document(self, document, env, building_slides): if need_reread: env.note_reread() + def _find_last_slide(self, node): + # Find all ancestors, including the doctree (dads[-1]) + ancestors, n = [], node + while n is not None: + ancestors.append(n) + n = n.parent + ancestors.reverse() + doctree = ancestors[0] + + if not slideconf.get_conf(self.document.settings.env.app.builder, doctree)['autoslides']: + return node.parent + #else it's one for the ancestors + + auto_level = slideconf.get_conf(self.document.settings.env.app.builder, doctree)['slide_levels'] + my_level = len(ancestors) -1 # Don't count the doctree + level = auto_level if my_level > auto_level else my_level-1 + + return ancestors[level] + + def _make_title_node(self, node, increment=True): """Generate a new title node for ``node``. ``node`` is a ``nextslide`` node. The title will use the node's parent's title, or the title specified as an argument. - """ - parent_title_node = node.parent.next_node(nodes.title) - nextslide_info = getattr( - parent_title_node, 'nextslide_info', - (parent_title_node.deepcopy().children, 1), - ) - nextslide_info = ( - nextslide_info[0], - nextslide_info[1] + 1, - ) + ancestor = self._find_last_slide(node) + parent_title_node = ancestor.next_node(nodes.title) + + nextslide_info = getattr(parent_title_node, 'nextslide_info', (parent_title_node.deepcopy().children, 1)) + nextslide_info = (nextslide_info[0], nextslide_info[1] + 1) if node.args: - textnodes, messages = node.state.inline_text( - node.args[0], - 1, - ) + textnodes, messages = node.state.inline_text(node.args[0], 1) new_title = nodes.title(node.args[0], '', *textnodes) - else: - title_nodes = nextslide_info[0][:] - if 'increment' in node.attributes: - title_nodes.append( - nodes.Text(' (%s)' % nextslide_info[1]) - ) - - new_title = nodes.title( - '', '', - *title_nodes - ) + title_nodes.append(nodes.Text(' (%s)' % nextslide_info[1])) + new_title = nodes.title('', '', *title_nodes) new_title.nextslide_info = nextslide_info return new_title + def visit_nextslide(self, node, building_slides): index = node.parent.index(node) - if (not building_slides or - not node.parent.children[index+1:]): + if not building_slides or not node.parent.children[index+1:]: # Just delete the directive-node, when not building slides or no content node.parent.replace(node, []) - - # nothing else to do return + #else # figure out where to hoist the subsequent content to + ancestor = self._find_last_slide(node) + forefather = ancestor.parent + insertion_point = forefather.index(ancestor) + 1 + + # truncate siblings, storing a reference to the rest of the content parent = node.parent - grandparent = node.parent.parent - insertion_point = grandparent.index(node.parent) + 1 - # truncate siblings, storing a reference to the rest of the - # content + # truncate siblings, storing a reference to the rest of the content new_children = parent.children[index+1:] parent.children = parent.children[:index+1] @@ -208,7 +198,7 @@ def visit_nextslide(self, node, building_slides): new_section['classes'].extend(node.get('classes')) # attach the section and delete the nextslide node - grandparent.insert(insertion_point, new_section) + forefather.insert(insertion_point, new_section) del node.parent[index] @@ -246,6 +236,7 @@ def get_conf(cls, builder, doctree=None): 'theme': builder.config.slide_theme, 'autoslides': builder.config.autoslides, 'slide_classes': [], + 'slide_levels': builder.config.slide_levels } # now look for a slideconf node in the doctree and update the conf @@ -314,9 +305,7 @@ def filter_doctree_for_slides(doctree): while current < num_children: child = doctree.children[current] - child.replace_self( - child.traverse(no_autoslides_filter) - ) + child.replace_self(child.traverse(no_autoslides_filter)) if len(doctree.children) == num_children: # nothing removed, increment current @@ -334,9 +323,7 @@ def process_slideconf_nodes(app, doctree, docname): # if autoslides is disabled and we're building slides, # replace the document tree with only explicit slide nodes - if (is_slides and - not slideconf.get_conf( - app.builder, doctree)['autoslides']): + if is_slides and not slideconf.get_conf(app.builder, doctree)['autoslides']: filter_doctree_for_slides(doctree) diff --git a/src/hieroglyph/themes/slides/slide.html b/src/hieroglyph/themes/slides/slide.html index d215757..d151537 100644 --- a/src/hieroglyph/themes/slides/slide.html +++ b/src/hieroglyph/themes/slides/slide.html @@ -1,7 +1,5 @@ -
- -{{ title }} +{% if title %}{{ title }} {% endif %} {{ content }} diff --git a/src/hieroglyph/themes/slides/static/styles.css b/src/hieroglyph/themes/slides/static/styles.css index b8d1b36..a11ef8b 100644 --- a/src/hieroglyph/themes/slides/static/styles.css +++ b/src/hieroglyph/themes/slides/static/styles.css @@ -1,6 +1,6 @@ @import url(fonts/stylesheet.css); -/* +/* Based on: Google HTML5 slides template Authors: Luke Mahé (code) @@ -27,8 +27,7 @@ body { height: 100%; min-height: 740px; - overflow-x: hidden; - overflow-y: auto; + overflow: hidden; background: rgb(215, 215, 215); background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); @@ -86,6 +85,10 @@ body { -moz-transition: -moz-transform .3s ease-out; -webkit-transition: -webkit-transform .3s ease-out; } + +/* Even when there is to much text, it should be visible on the current slide*/ +.slides > article.current { overflow-y: auto; overflow-x: hidden} + .slides.layout-widescreen > article { margin-left: -550px; width: 1100px; @@ -415,10 +418,7 @@ h2 { padding: 0; margin: 0; - margin-top: 465px; padding-right: 40px; - /* position: absolute; */ - /* bottom: 150px; */ font-weight: 600; @@ -433,6 +433,7 @@ h3 { padding: 0; margin: 0; + margin-top: 1em; padding-right: 40px; font-weight: 600; @@ -458,8 +459,6 @@ ul { margin: 0; padding: 0; - margin-top: 40px; - margin-left: .75em; } ul ul { diff --git a/src/hieroglyph/themes/slides2/slide.html b/src/hieroglyph/themes/slides2/slide.html index 47c77e3..e1c34e0 100644 --- a/src/hieroglyph/themes/slides2/slide.html +++ b/src/hieroglyph/themes/slides2/slide.html @@ -1,15 +1,10 @@ - -
- {{ title }} -
-
- {{ content }} + +
{% if title %}{{ title }} {% endif %}
+
+ {{ content }} + + {% if config.slide_numbers %}
{{ slide_number }}
{% endif %} + {% if config.slide_footer %}{% endif %} +
+
-{% if config.slide_numbers %} -
{{ slide_number }}
-{% endif %} -{% if config.slide_footer %} - -{% endif %} -
-
diff --git a/src/hieroglyph/themes/slides2/static/theme/css/default.css b/src/hieroglyph/themes/slides2/static/theme/css/default.css index 610955a..94c9e17 100644 --- a/src/hieroglyph/themes/slides2/static/theme/css/default.css +++ b/src/hieroglyph/themes/slides2/static/theme/css/default.css @@ -136,7 +136,7 @@ slides { slides > slide { display: block; position: absolute; - overflow: hidden; + overflow: auto; left: 50%; top: 50%; -moz-box-sizing: border-box; diff --git a/src/hieroglyph/writer.py b/src/hieroglyph/writer.py index ce946fa..7da0f49 100644 --- a/src/hieroglyph/writer.py +++ b/src/hieroglyph/writer.py @@ -4,96 +4,50 @@ from sphinx.locale import _ from docutils.writers.html4css1 import HTMLTranslator as BaseTranslator from sphinx.writers.html import HTMLTranslator - from hieroglyph import html -from hieroglyph.directives import ( - slide, - slideconf, -) - - -def depart_title(self, node): - - # XXX Because we want to inject our link into the title, this is - # largely copy-pasta'd from sphinx.html.writers.HtmlTranslator. - - close_tag = self.context[-1] - - if (self.permalink_text and self.builder.add_permalinks and - node.parent.hasattr('ids') and node.parent['ids']): - aname = node.parent['ids'][0] - - if close_tag.startswith('') - - self.body.append(u'%s' % ( - _('Permalink to this headline'), - self.permalink_text)) - - self.body.append( - u'%s' % ( - _('Slides'), - self.builder.app.config.slide_html_slide_link_symbol, - )) - - if not close_tag.startswith('') - - BaseTranslator.depart_title(self, node) +from hieroglyph.directives import slideconf class SlideData(object): def __init__(self, translator, **kwargs): + # set during init, see below (there only 1 call!) self._translator = translator - + self.id = '' self.level = 0 - self.title = '' - self.content = '' - self.classes = [] self.slide_number = 0 - self.id = '' + self.classes = [] - for name, value in kwargs.items(): - setattr(self, name, value) + # set after init (direct write) + self.title = None + self.content = '' - def _filter_classes(self, include=None, exclude=None): + # no other attrs are used then above! + for name, value in kwargs.items(): setattr(self, name, value) + + def _filter_classes(self, include=None, exclude=None): classes = self.classes[:] if include is not None: - classes = [ - c[len(include):] for c in classes - if c.startswith(include) - ] - + classes = [ c[len(include):] for c in classes if c.startswith(include) ] if exclude is not None: - classes = [ - c for c in classes - if not c.startswith(exclude) - ] - + classes = [ c for c in classes if not c.startswith(exclude) ] return classes - def get_slide_context(self): + + def _get_slide_context(self): """Return the context dict for rendering this slide.""" - return { - 'title': self.title, - 'level': self.level, - 'content': self.content, - 'classes': self.classes, - 'slide_classes': self._filter_classes(exclude='content-'), - 'content_classes': self._filter_classes(include='content-'), - 'slide_number': self.slide_number, - 'config': self._translator.builder.config, - 'id': self.id, - } + return { 'title': self.title, + 'level': self.level, + 'content': self.content, + 'classes': self.classes, + 'slide_classes': self._filter_classes(exclude='content-'), + 'content_classes': self._filter_classes(include='content-'), + 'slide_number': self.slide_number, + 'config': self._translator.builder.config, + 'id': self.id } class BaseSlideTranslator(HTMLTranslator): @@ -102,21 +56,21 @@ def __init__(self, *args, **kwargs): HTMLTranslator.__init__(self, *args, **kwargs) - self.section_count = 0 - self.body_stack = [] + self.slide_number = 0 + self._body_stack = [] self.current_slide = None - self.slide_data = [] + def push_body(self): """Push the current body onto the stack and create an empty one.""" - - self.body_stack.append(self.body) + self._body_stack.append(self.body) self.body = [] def pop_body(self): - """Replace the current body with the last one pushed to the stack.""" - - self.body = self.body_stack.pop() + """Replace the current body with the last pushed one. And return the popped one.""" + body= self.body + self.body = self._body_stack.pop() + return body def visit_slideconf(self, node): pass @@ -124,144 +78,54 @@ def visit_slideconf(self, node): def depart_slideconf(self, node): pass - def _add_slide_number(self, slide_no): - """Add the slide number to the output if enabled.""" - - if self.builder.config.slide_numbers: - self.body.append( - '\n
%s
\n' % (slide_no,), - ) - def _add_slide_footer(self, slide_no): - """Add the slide footer to the output if enabled.""" + def slide_start(self, node): + """A pseudo visitor to start (and end) a slide""" - if self.builder.config.slide_footer: - self.body.append( - '\n\n' % ( - self.builder.config.slide_footer, - ), - ) - - def visit_slide(self, node): - - from hieroglyph import builder - - slide_level = node.attributes.get('level', self.section_level) - - if slide_level > self.builder.config.slide_levels: - # dummy for matching div's - self.body.append( - self.starttag( - node, 'div', CLASS='section level-%s' % slide_level) - ) - node.tag_name = 'div' - else: + self.slide_number +=1 + classes = node.get('classes') + if not classes: slide_conf = slideconf.get_conf(self.builder, node.document) - if (builder.building_slides(self.builder.app) and - slide_conf['autoslides'] and - isinstance(node.parent, nodes.section) and - not getattr(node.parent, 'closed', False)): - - # we're building slides and creating slides from - # sections; close the previous section, if needed - self.depart_slide(node.parent) - - # don't increment section_count until we've (potentially) - # closed the previous slide - self.section_count += 1 - - node.closed = False - - classes = node.get('classes') - if not classes: - classes = slide_conf['slide_classes'] - - # self.body.append( - # self.starttag( - # node, 'article', - # CLASS='%s slide level-%s' % ( - # ' '.join(classes), - # slide_level, - # ), - # ) - # ) - node.tag_name = 'article' - - slide_id = node.get('ids') - if slide_id: - slide_id = slide_id[0] - else: - slide_id = '' - - assert self.current_slide is None - self.current_slide = SlideData( - self, - id=slide_id, - level=slide_level, - classes=classes, - slide_number=self.section_count, - ) - self.push_body() - - def depart_slide(self, node): + classes = slide_conf['slide_classes'] - if self.current_slide and not getattr(node, 'closed', False): + try: + ids = node.get('ids')[0] + except IndexError: + ids =str(abs(hash(node))) # Just some string-value - # mark the slide closed - node.closed = True + self.push_body() # Save old data and collect all upto slide_end + self.current_slide = SlideData(translator=self, id=ids, level=self.section_level, slide_number=self.slide_number, classes=classes) - # self._add_slide_footer(self.section_count) - # self._add_slide_number(self.section_count) - # self.body.append( - # '\n\n' % getattr(node, 'tag_name', 'article') - # ) - self.current_slide.content = ''.join(self.body) - self.pop_body() - rendered_slide = self.builder.templates.render( - 'slide.html', - self.current_slide.get_slide_context(), - ) - self.body.append(rendered_slide) - self.slide_data.append(self.current_slide) - self.current_slide = None + def slide_end(self, node): + """A pseudo visitor to (start and) end a slide""" - def visit_title(self, node): + # All`body` of the slide is collected; get it and pop the body + slide_body = self.pop_body() - self.push_body() + slide = self.current_slide + if slide is None: + import warnings + warnings.warn("Trying to end a slide that does not exist. \n\tnode:", node, "\n\tbody:", slide_body) + return - if (isinstance(node.parent, slide) or - node.parent.attributes.get('include-as-slide', False)): - slide_level = node.parent.attributes.get( - 'level', - self.section_level) - level = max( - slide_level + self.initial_header_level - 1, - 1, - ) - self.current_slide.level = level + slide.content = u''.join(slide_body) + rendered_slide = self.builder.templates.render('slide.html', slide._get_slide_context()) + self.body.append(rendered_slide) + self.current_slide = None - # tag = 'h%s' % level - # self.body.append(self.starttag(node, tag, '')) - # self.context.append('\n' % tag) - if self.current_slide and isinstance(node.parent, (nodes.section, slide)): + def visit_title(self, node): + if (self.current_slide is not None) and (self.current_slide.title is None): + # This is the first title in on a new slide -> Put in current_slide title. Not in the body/content self.current_slide.title = node.astext().strip() + raise nodes.SkipNode # will skip depart_title! else: HTMLTranslator.visit_title(self, node) + # Note: depart_title() is inherited. - def depart_title(self, node): - - if self.current_slide and isinstance(node.parent, (nodes.section, slide)): - self.current_slide.title = ''.join(self.body) - self.pop_body() - else: - HTMLTranslator.depart_title(self, node) - title = ''.join(self.body) - self.pop_body() - self.body.append(title) def visit_block_quote(self, node): quote_slide_tags = ['paragraph', 'attribution'] @@ -299,30 +163,46 @@ def visit_block_quote(self, node): class SlideTranslator(BaseSlideTranslator): def visit_section(self, node): + # Increase the section_level, and 'maybe' start a new slide + self.section_level += 1 + self._maybe_new_slide(node) # we might need a new slide (stop one and start one) - # XXX: We're actually removing content that's not in slide - # nodes with autoslides is false, so it's not clear that we - # even need this guard. - if (slideconf.get_conf(self.builder, node.document)['autoslides'] or - node.attributes.get('include-as-slide', False)): + def depart_section(self, node): + self.section_level -= 1 - self.section_level += 1 - return self.visit_slide(node) - def depart_section(self, node): + def _maybe_new_slide(self, node): + """Determine whether a slide-transition is needed, and insert it when needed. + Also return True/False depending on that need.""" - if (slideconf.get_conf(self.builder, node.document)['autoslides'] or - node.attributes.get('include-as-slide', False)): + if not slideconf.get_conf(self.builder, node.document)['autoslides']: + return False + # else - if self.section_level > self.builder.config.slide_levels: - self.body.append('') - else: - self.depart_slide(node) + slide_levels = self.builder.config.slide_levels - self.section_level -= 1 + if self.section_level <= slide_levels: + if getattr(self, 'slide_open', False): # Basically: Skip slide_end, for when starting the first slide! + self.slide_end(node) - def depart_title(self, node): + self.slide_start(node) + self.slide_open=True + + return True + else: + return False + + + def visit_document(self, node): # Only to TRACE it + BaseSlideTranslator.visit_document(self, node) + + def depart_document(self, node): + if getattr(self, 'slide_open', False): #Close the last slide + self.slide_end(node) + BaseSlideTranslator.depart_document(self, node) + + def depart_title(self, node): if node.parent.hasattr('ids') and node.parent['ids']: aname = node.parent['ids'][0] @@ -351,6 +231,17 @@ def visit_start_of_file(self, node): BaseSlideTranslator.visit_start_of_file(self, node) + def visit_slide(self, node): + if getattr(self, 'slide_open', False): # end an "auto slide" + self.slide_end(node) + self.slide_start(node); + self.slide_open=True + + def depart_slide(self, node): + self.slide_end(node); + self.slide_open=False + + class SingleFileSlideTranslator(SlideTranslator): def visit_compound(self, node):