#!/usr/bin/env python # -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Bootstrap RST # Copyright (c) 2014, Nicolas P. Rougier # Distributed under the (new) BSD License. See LICENSE.txt for more info. # ----------------------------------------------------------------------------- import sys, os, re from docutils import nodes, utils from docutils.parsers.rst.directives import images from docutils.transforms import TransformError, Transform, parts from docutils.parsers.rst import Directive, directives, states, roles from docutils.nodes import fully_normalize_name, whitespace_normalize_name from docutils.parsers.rst.roles import set_classes from docutils.io import StringOutput from docutils.core import Publisher from pelican import signals from pelican.readers import RstReader, PelicanHTMLTranslator from .roles import * from .directives import * class HTMLTranslator(PelicanHTMLTranslator): """ This is a translator class for the docutils system. """ def visit_h1(self, node): self.body.append('

%s

' % node.children[0]) raise nodes.SkipNode def visit_h2(self, node): self.body.append('

%s

' % node.children[0]) raise nodes.SkipNode def visit_h3(self, node): self.body.append('

%s

' % node.children[0]) raise nodes.SkipNode def visit_h4(self, node): self.body.append('

%s

' % node.children[0]) raise nodes.SkipNode def visit_h5(self, node): self.body.append('
%s
' % node.children[0]) raise nodes.SkipNode def visit_h6(self, node): self.body.append('
%s
' % node.children[0]) raise nodes.SkipNode def visit_label_default(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_label_primary(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_label_success(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_label_info(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_label_warning(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_label_danger(self, node): self.body.append( '%s' % node.children[0]) raise nodes.SkipNode def visit_page_row(self, node): self.body.append(self.starttag(node,'div')) def depart_page_row(self, node): self.body.append('\n') def visit_page_column(self, node): self.body.append(self.starttag(node,'div')) def depart_page_column(self, node): self.body.append('\n') def visit_button(self, node): btn_classes = { 'primary' : 'btn-primary', 'success' : 'btn-success', 'info' : 'btn-info', 'warning' : 'btn-warning', 'danger' : 'btn-danger', 'link' : 'btn-link', 'outline' : 'btn-outline', 'tiny' : 'btn-xs', 'small' : 'btn-sm', 'large' : 'btn-lg', 'block' : 'btn-block', 'active' : 'btn-active' } classes = 'btn ' flag = False for node_class in node['classes']: if node_class in ['primary', 'success', 'warning' 'info', 'link', 'danger', 'outline']: flag = True btn_class = btn_classes.get(node_class, None) if btn_class: classes += btn_class + ' ' if flag == False: classes += 'btn-default' target = node['target'] properties = '' # Disabled if 'disabled' in node['classes']: if target: properties += ' disabled="disabled"' else: classes += ' disabled' # Data toggle if 'toggle' in node['classes']: classes += ' dropdown-toggle ' properties += ' data-toggle="dropdown"' if target: properties += ' role="button"' anchor = '' % (target,classes,properties) self.body.append(anchor) else: properties += ' type="button"' button = '\n') def visit_progress(self, node): prg_classes = { 'success' : 'progress-bar-success', 'info' : 'progress-bar-info', 'warning' : 'progress-bar-warning', 'danger' : 'progress-bar-danger' } label = node['label'] classes = 'progress-bar' flag = False for nodeclass in node['classes']: flag = True classes += ' ' + prg_classes.get(nodeclass, '') if flag == False: classes += ' progress-bar-default' properties = 'role="progress-bar"' properties += ' aria-valuenow="%d"' % int(node['value']) properties += ' aria-valuemin="%d"' % int(node['value_min']) properties += ' aria-valuemax="%d"' % int(node['value_max']) properties += ' style="width: %d%%";' % int(node['value']) if 'active' in node['classes']: self.body.append('
') elif 'striped' in node['classes']: self.body.append('
') else: self.body.append('
') self.body.append( '
%s
' % (classes,properties,label)) self.body.append('
') raise nodes.SkipNode def visit_alert(self, node): self.body.append(self.starttag(node, 'div', CLASS='alert')) if node.dismissable: self.body.append( u"""""") def depart_alert(self, node): self.body.append('
\n') def visit_callout(self, node): self.body.append(self.starttag(node, 'div', CLASS='bs-callout')) def depart_callout(self, node): self.body.append('
\n') # overwritten def visit_definition_list(self, node): list_class = node.parent.get('list-class', []) list_class.append('docutils') list_class = ' '.join(list_class) self.body.append(self.starttag(node, 'dl', CLASS=list_class)) # overwritten def visit_sidebar(self, node): self.body.append(self.starttag(node, 'div', CLASS='col-md-3 col-md-push-9')) self.body.append(self.starttag(node, 'div', CLASS='bs-docs-sidebar hidden-print affix-top')) self.body.append(self.starttag(node, 'div', CLASS='sidebar')) self.set_first_last(node) self.in_sidebar = True # overwritten def depart_sidebar(self, node): self.body.append('\n') self.body.append('\n') self.body.append('\n') # Opening tag for body self.body.append(self.starttag(node, 'div', CLASS='col-md-9 col-md-pull-3')) self.in_sidebar = False # overwritten : removed compact paragraph # def visit_paragraph(self, node): # if self.should_be_compact_paragraph(node): # self.context.append('') # else: # self.body.append(self.starttag(node, 'p', '')) # self.context.append('

\n') # overwritten: remove border=1, replace docutils/table class def visit_table(self, node): self.context.append(self.compact_p) self.compact_p = True #classes = ' '.join(['docutils', self.settings.table_style]).strip() classes = ' '.join(['table', self.settings.table_style]).strip() self.body.append(self.starttag(node, 'table', CLASS=classes)) # overwritten : removed 'container' class def visit_container(self, node): self.body.append(self.starttag(node, 'div', CLASS='')) # overwritten: get rid of
tag def depart_header(self, node): start = self.context.pop() header = [self.starttag(node, 'div', CLASS='header')] header.extend(self.body[start:]) header.append('\n\n') self.body_prefix.extend(header) self.header.extend(header) del self.body[start:] # overwritten: get rid of
tag def depart_footer(self, node): start = self.context.pop() footer = [self.starttag(node, 'div', CLASS='footer')] footer.extend(self.body[start:]) footer.append('\n\n') self.footer.extend(footer) self.body_suffix[:0] = footer del self.body[start:] # overwritten 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: self.head.append(self.math_header) # skip content-type meta tag with interpolated charset value: self.html_head.extend(self.head[1:]) # self.body_prefix.append(self.starttag(node, 'div', CLASS='document')) self.body_prefix.append(self.starttag(node, 'div', CLASS='container')) # self.body_suffix.insert(0, '\n') self.fragment.extend(self.body) # self.fragment is the "naked" body self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo + self.docinfo + self.body + self.body_suffix[:-1]) assert not self.context, 'len(context) = %s' % len(self.context) # ----------------------------------------------------------------------------- class RSTReader(RstReader): """ A custom RST reader that behaves exactly like its parent class RstReader with the difference that it uses our HTMLTranslator """ def _get_publisher(self, source_path): extra_params = {'initial_header_level': '2', 'syntax_highlight': 'short', 'input_encoding': 'utf-8'} user_params = self.settings.get('DOCUTILS_SETTINGS') if user_params: extra_params.update(user_params) pub = Publisher(destination_class=StringOutput) pub.set_components('standalone', 'restructuredtext', 'html') pub.writer.translator_class = HTMLTranslator pub.process_programmatic_settings(None, extra_params, None) pub.set_source(source_path=source_path) pub.publish() return pub def add_reader(readers): readers.reader_classes['rst'] = RSTReader def register(): signals.readers_init.connect(add_reader)