summaryrefslogtreecommitdiffstats
path: root/nikola/plugins/compile/rest
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-02-03 19:17:00 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-02-03 19:17:00 -0500
commit3a0d66f07b112b6d2bdc2b57bbf717a89a351ce6 (patch)
treea7cf56282e54f05785243bc1e903d6594f2c06ba /nikola/plugins/compile/rest
parent787b97a4cb24330b36f11297c6d3a7a473a907d0 (diff)
New upstream version 8.1.2.upstream/8.1.2
Diffstat (limited to 'nikola/plugins/compile/rest')
-rw-r--r--nikola/plugins/compile/rest/__init__.py277
-rw-r--r--nikola/plugins/compile/rest/chart.plugin4
-rw-r--r--nikola/plugins/compile/rest/chart.py91
-rw-r--r--nikola/plugins/compile/rest/doc.plugin4
-rw-r--r--nikola/plugins/compile/rest/doc.py81
-rw-r--r--nikola/plugins/compile/rest/gist.plugin4
-rw-r--r--nikola/plugins/compile/rest/gist.py4
-rw-r--r--nikola/plugins/compile/rest/listing.plugin4
-rw-r--r--nikola/plugins/compile/rest/listing.py42
-rw-r--r--nikola/plugins/compile/rest/media.plugin4
-rw-r--r--nikola/plugins/compile/rest/media.py30
-rw-r--r--nikola/plugins/compile/rest/post_list.plugin8
-rw-r--r--nikola/plugins/compile/rest/post_list.py183
-rw-r--r--nikola/plugins/compile/rest/slides.plugin14
-rw-r--r--nikola/plugins/compile/rest/slides.py80
-rw-r--r--nikola/plugins/compile/rest/soundcloud.plugin4
-rw-r--r--nikola/plugins/compile/rest/soundcloud.py46
-rw-r--r--nikola/plugins/compile/rest/thumbnail.plugin4
-rw-r--r--nikola/plugins/compile/rest/thumbnail.py12
-rw-r--r--nikola/plugins/compile/rest/vimeo.plugin2
-rw-r--r--nikola/plugins/compile/rest/vimeo.py25
-rw-r--r--nikola/plugins/compile/rest/youtube.plugin2
-rw-r--r--nikola/plugins/compile/rest/youtube.py33
23 files changed, 488 insertions, 470 deletions
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py
index b99e872..44da076 100644
--- a/nikola/plugins/compile/rest/__init__.py
+++ b/nikola/plugins/compile/rest/__init__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -26,87 +26,138 @@
"""reStructuredText compiler for Nikola."""
-from __future__ import unicode_literals
import io
+import logging
import os
import docutils.core
import docutils.nodes
+import docutils.transforms
import docutils.utils
import docutils.io
import docutils.readers.standalone
-import docutils.writers.html4css1
+import docutils.writers.html5_polyglot
+import docutils.parsers.rst.directives
+from docutils.parsers.rst import roles
+from nikola.nikola import LEGAL_VALUES
+from nikola.metadata_extractors import MetaCondition
from nikola.plugin_categories import PageCompiler
-from nikola.utils import unicode_str, get_logger, makedirs, write_metadata, STDERR_HANDLER
+from nikola.utils import (
+ makedirs,
+ write_metadata,
+ LocaleBorg,
+ map_metadata
+)
class CompileRest(PageCompiler):
-
"""Compile reStructuredText into HTML."""
name = "rest"
friendly_name = "reStructuredText"
demote_headers = True
logger = None
-
- def _read_extra_deps(self, post):
- """Read contents of .dep file and returns them as a list."""
- dep_path = post.base_path + '.dep'
- if os.path.isfile(dep_path):
- with io.open(dep_path, 'r+', encoding='utf8') as depf:
- deps = [l.strip() for l in depf.readlines()]
- return deps
- return []
-
- def register_extra_dependencies(self, post):
- """Add dependency to post object to check .dep file."""
- post.add_dependency(lambda: self._read_extra_deps(post), 'fragment')
-
- def compile_html_string(self, data, source_path=None, is_two_file=True):
+ supports_metadata = True
+ metadata_conditions = [(MetaCondition.config_bool, "USE_REST_DOCINFO_METADATA")]
+
+ def read_metadata(self, post, lang=None):
+ """Read the metadata from a post, and return a metadata dict."""
+ if lang is None:
+ lang = LocaleBorg().current_lang
+ source_path = post.translated_source_path(lang)
+
+ # Silence reST errors, some of which are due to a different
+ # environment. Real issues will be reported while compiling.
+ null_logger = logging.getLogger('NULL')
+ null_logger.setLevel(1000)
+ with io.open(source_path, 'r', encoding='utf-8-sig') as inf:
+ data = inf.read()
+ _, _, _, document = rst2html(data, logger=null_logger, source_path=source_path, transforms=self.site.rst_transforms)
+ meta = {}
+ if 'title' in document:
+ meta['title'] = document['title']
+ for docinfo in document.traverse(docutils.nodes.docinfo):
+ for element in docinfo.children:
+ if element.tagname == 'field': # custom fields (e.g. summary)
+ name_elem, body_elem = element.children
+ name = name_elem.astext()
+ value = body_elem.astext()
+ elif element.tagname == 'authors': # author list
+ name = element.tagname
+ value = [element.astext() for element in element.children]
+ else: # standard fields (e.g. address)
+ name = element.tagname
+ value = element.astext()
+ name = name.lower()
+
+ meta[name] = value
+
+ # Put 'authors' meta field contents in 'author', too
+ if 'authors' in meta and 'author' not in meta:
+ meta['author'] = '; '.join(meta['authors'])
+
+ # Map metadata from other platforms to names Nikola expects (Issue #2817)
+ map_metadata(meta, 'rest_docinfo', self.site.config)
+ return meta
+
+ def compile_string(self, data, source_path=None, is_two_file=True, post=None, lang=None):
"""Compile reST into HTML strings."""
# If errors occur, this will be added to the line number reported by
# docutils so the line number matches the actual line number (off by
# 7 with default metadata, could be more or less depending on the post).
add_ln = 0
if not is_two_file:
- m_data, data = self.split_metadata(data)
+ m_data, data = self.split_metadata(data, post, lang)
add_ln = len(m_data.splitlines()) + 1
default_template_path = os.path.join(os.path.dirname(__file__), 'template.txt')
- output, error_level, deps = rst2html(
- data, settings_overrides={
- 'initial_header_level': 1,
- 'record_dependencies': True,
- 'stylesheet_path': None,
- 'link_stylesheet': True,
- 'syntax_highlight': 'short',
- 'math_output': 'mathjax',
- 'template': default_template_path,
- }, logger=self.logger, source_path=source_path, l_add_ln=add_ln, transforms=self.site.rst_transforms)
- if not isinstance(output, unicode_str):
+ settings_overrides = {
+ 'initial_header_level': 1,
+ 'record_dependencies': True,
+ 'stylesheet_path': None,
+ 'link_stylesheet': True,
+ 'syntax_highlight': 'short',
+ # This path is not used by Nikola, but we need something to silence
+ # warnings about it from reST.
+ 'math_output': 'mathjax /assets/js/mathjax.js',
+ 'template': default_template_path,
+ 'language_code': LEGAL_VALUES['DOCUTILS_LOCALES'].get(LocaleBorg().current_lang, 'en'),
+ 'doctitle_xform': self.site.config.get('USE_REST_DOCINFO_METADATA'),
+ 'file_insertion_enabled': self.site.config.get('REST_FILE_INSERTION_ENABLED'),
+ }
+
+ from nikola import shortcodes as sc
+ new_data, shortcodes = sc.extract_shortcodes(data)
+ if self.site.config.get('HIDE_REST_DOCINFO', False):
+ self.site.rst_transforms.append(RemoveDocinfo)
+ output, error_level, deps, _ = rst2html(
+ new_data, settings_overrides=settings_overrides, logger=self.logger, source_path=source_path, l_add_ln=add_ln, transforms=self.site.rst_transforms)
+ if not isinstance(output, str):
# To prevent some weird bugs here or there.
# Original issue: empty files. `output` became a bytestring.
output = output.decode('utf-8')
- return output, error_level, deps
- def compile_html(self, source, dest, is_two_file=True):
- """Compile source file into HTML and save as dest."""
+ output, shortcode_deps = self.site.apply_shortcodes_uuid(output, shortcodes, filename=source_path, extra_context={'post': post})
+ return output, error_level, deps, shortcode_deps
+
+ def compile(self, source, dest, is_two_file=True, post=None, lang=None):
+ """Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
error_level = 100
- with io.open(dest, "w+", encoding="utf8") as out_file:
- with io.open(source, "r", encoding="utf8") as in_file:
+ with io.open(dest, "w+", encoding="utf-8") as out_file:
+ with io.open(source, "r", encoding="utf-8-sig") as in_file:
data = in_file.read()
- output, error_level, deps = self.compile_html_string(data, source, is_two_file)
+ output, error_level, deps, shortcode_deps = self.compile_string(data, source, is_two_file, post, lang)
out_file.write(output)
- deps_path = dest + '.dep'
- if deps.list:
- deps.list = [p for p in deps.list if p != dest] # Don't depend on yourself (#1671)
- with io.open(deps_path, "w+", encoding="utf8") as deps_file:
- deps_file.write('\n'.join(deps.list))
+ if post is None:
+ if deps.list:
+ self.logger.error(
+ "Cannot save dependencies for post {0} (post unknown)",
+ source)
else:
- if os.path.isfile(deps_path):
- os.unlink(deps_path)
+ post._depfile[dest] += deps.list
+ post._depfile[dest] += shortcode_deps
if error_level < 3:
return True
else:
@@ -124,23 +175,21 @@ class CompileRest(PageCompiler):
makedirs(os.path.dirname(path))
if not content.endswith('\n'):
content += '\n'
- with io.open(path, "w+", encoding="utf8") as fd:
+ with io.open(path, "w+", encoding="utf-8") as fd:
if onefile:
- fd.write(write_metadata(metadata))
- fd.write('\n')
+ fd.write(write_metadata(metadata, comment_wrap=False, site=self.site, compiler=self))
fd.write(content)
def set_site(self, site):
"""Set Nikola site."""
- super(CompileRest, self).set_site(site)
+ super().set_site(site)
self.config_dependencies = []
for plugin_info in self.get_compiler_extensions():
self.config_dependencies.append(plugin_info.name)
plugin_info.plugin_object.short_help = plugin_info.description
- self.logger = get_logger('compile_rest', STDERR_HANDLER)
if not site.debug:
- self.logger.level = 4
+ self.logger.level = logging.WARNING
def get_observer(settings):
@@ -150,19 +199,25 @@ def get_observer(settings):
Error code mapping:
- +------+---------+------+----------+
- | dNUM | dNAME | lNUM | lNAME | d = docutils, l = logbook
- +------+---------+------+----------+
- | 0 | DEBUG | 1 | DEBUG |
- | 1 | INFO | 2 | INFO |
- | 2 | WARNING | 4 | WARNING |
- | 3 | ERROR | 5 | ERROR |
- | 4 | SEVERE | 6 | CRITICAL |
- +------+---------+------+----------+
+ +----------+----------+
+ | docutils | logging |
+ +----------+----------+
+ | DEBUG | DEBUG |
+ | INFO | INFO |
+ | WARNING | WARNING |
+ | ERROR | ERROR |
+ | SEVERE | CRITICAL |
+ +----------+----------+
"""
- errormap = {0: 1, 1: 2, 2: 4, 3: 5, 4: 6}
+ errormap = {
+ docutils.utils.Reporter.DEBUG_LEVEL: logging.DEBUG,
+ docutils.utils.Reporter.INFO_LEVEL: logging.INFO,
+ docutils.utils.Reporter.WARNING_LEVEL: logging.WARNING,
+ docutils.utils.Reporter.ERROR_LEVEL: logging.ERROR,
+ docutils.utils.Reporter.SEVERE_LEVEL: logging.CRITICAL
+ }
text = docutils.nodes.Element.astext(msg)
- line = msg['line'] + settings['add_ln'] if 'line' in msg else 0
+ line = msg['line'] + settings['add_ln'] if 'line' in msg else ''
out = '[{source}{colon}{line}] {text}'.format(
source=settings['source'], colon=(':' if line else ''),
line=line, text=text)
@@ -172,12 +227,14 @@ def get_observer(settings):
class NikolaReader(docutils.readers.standalone.Reader):
-
"""Nikola-specific docutils reader."""
+ config_section = 'nikola'
+
def __init__(self, *args, **kwargs):
"""Initialize the reader."""
self.transforms = kwargs.pop('transforms', [])
+ self.logging_settings = kwargs.pop('nikola_logging_settings', {})
docutils.readers.standalone.Reader.__init__(self, *args, **kwargs)
def get_transforms(self):
@@ -188,15 +245,26 @@ class NikolaReader(docutils.readers.standalone.Reader):
"""Create and return a new empty document tree (root node)."""
document = docutils.utils.new_document(self.source.source_path, self.settings)
document.reporter.stream = False
- document.reporter.attach_observer(get_observer(self.l_settings))
+ document.reporter.attach_observer(get_observer(self.logging_settings))
return document
+def shortcode_role(name, rawtext, text, lineno, inliner,
+ options={}, content=[]):
+ """Return a shortcode role that passes through raw inline HTML."""
+ return [docutils.nodes.raw('', text, format='html')], []
+
+
+roles.register_canonical_role('raw-html', shortcode_role)
+roles.register_canonical_role('html', shortcode_role)
+roles.register_canonical_role('sc', shortcode_role)
+
+
def add_node(node, visit_function=None, depart_function=None):
"""Register a Docutils node class.
This function is completely optional. It is a same concept as
- `Sphinx add_node function <http://sphinx-doc.org/ext/appapi.html#sphinx.application.Sphinx.add_node>`_.
+ `Sphinx add_node function <http://sphinx-doc.org/extdev/appapi.html#sphinx.application.Sphinx.add_node>`_.
For example::
@@ -208,7 +276,7 @@ def add_node(node, visit_function=None, depart_function=None):
self.site = site
directives.register_directive('math', MathDirective)
add_node(MathBlock, visit_Math, depart_Math)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
class MathDirective(Directive):
def run(self):
@@ -227,16 +295,52 @@ def add_node(node, visit_function=None, depart_function=None):
"""
docutils.nodes._add_node_class_names([node.__name__])
if visit_function:
- setattr(docutils.writers.html4css1.HTMLTranslator, 'visit_' + node.__name__, visit_function)
+ setattr(docutils.writers.html5_polyglot.HTMLTranslator, 'visit_' + node.__name__, visit_function)
if depart_function:
- setattr(docutils.writers.html4css1.HTMLTranslator, 'depart_' + node.__name__, depart_function)
+ setattr(docutils.writers.html5_polyglot.HTMLTranslator, 'depart_' + node.__name__, depart_function)
+
+
+# Output <code> for ``double backticks``. (Code and extra logic based on html4css1 translator)
+def visit_literal(self, node):
+ """Output <code> for double backticks."""
+ # special case: "code" role
+ classes = node.get('classes', [])
+ if 'code' in classes:
+ # filter 'code' from class arguments
+ node['classes'] = [cls for cls in classes if cls != 'code']
+ self.body.append(self.starttag(node, 'code', ''))
+ return
+ self.body.append(
+ self.starttag(node, 'code', '', CLASS='docutils literal'))
+ text = node.astext()
+ for token in self.words_and_spaces.findall(text):
+ if token.strip():
+ # Protect text like "--an-option" and the regular expression
+ # ``[+]?(\d+(\.\d*)?|\.\d+)`` from bad line wrapping
+ if self.in_word_wrap_point.search(token):
+ self.body.append('<span class="pre">%s</span>'
+ % self.encode(token))
+ else:
+ self.body.append(self.encode(token))
+ elif token in ('\n', ' '):
+ # Allow breaks at whitespace:
+ self.body.append(token)
+ else:
+ # Protect runs of multiple spaces; the last space can wrap:
+ self.body.append('&nbsp;' * (len(token) - 1) + ' ')
+ self.body.append('</code>')
+ # Content already processed:
+ raise docutils.nodes.SkipNode
+
+
+setattr(docutils.writers.html5_polyglot.HTMLTranslator, 'visit_literal', visit_literal)
def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
destination_path=None, reader=None,
parser=None, parser_name='restructuredtext', writer=None,
- writer_name='html', settings=None, settings_spec=None,
- settings_overrides=None, config_section=None,
+ writer_name='html5_polyglot', settings=None, settings_spec=None,
+ settings_overrides=None, config_section='nikola',
enable_exit_status=None, logger=None, l_add_ln=0, transforms=None):
"""Set up & run a ``Publisher``, and return a dictionary of document parts.
@@ -249,20 +353,22 @@ def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
publish_parts(..., settings_overrides={'input_encoding': 'unicode'})
- Parameters: see `publish_programmatically`.
+ For a description of the parameters, see `publish_programmatically`.
WARNING: `reader` should be None (or NikolaReader()) if you want Nikola to report
reStructuredText syntax errors.
"""
if reader is None:
- reader = NikolaReader(transforms=transforms)
# For our custom logging, we have special needs and special settings we
# specify here.
# logger a logger from Nikola
# source source filename (docutils gets a string)
- # add_ln amount of metadata lines (see comment in compile_html above)
- reader.l_settings = {'logger': logger, 'source': source_path,
- 'add_ln': l_add_ln}
+ # add_ln amount of metadata lines (see comment in CompileRest.compile above)
+ reader = NikolaReader(transforms=transforms,
+ nikola_logging_settings={
+ 'logger': logger, 'source': source_path,
+ 'add_ln': l_add_ln
+ })
pub = docutils.core.Publisher(reader, parser, writer, settings=settings,
source_class=source_class,
@@ -275,4 +381,23 @@ def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
pub.set_destination(None, destination_path)
pub.publish(enable_exit_status=enable_exit_status)
- return pub.writer.parts['docinfo'] + pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies
+ return pub.writer.parts['docinfo'] + pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies, pub.document
+
+
+# Alignment helpers for extensions
+_align_options_base = ('left', 'center', 'right')
+
+
+def _align_choice(argument):
+ return docutils.parsers.rst.directives.choice(argument, _align_options_base + ("none", ""))
+
+
+class RemoveDocinfo(docutils.transforms.Transform):
+ """Remove docinfo nodes."""
+
+ default_priority = 870
+
+ def apply(self):
+ """Remove docinfo nodes."""
+ for node in self.document.traverse(docutils.nodes.docinfo):
+ node.parent.remove(node)
diff --git a/nikola/plugins/compile/rest/chart.plugin b/nikola/plugins/compile/rest/chart.plugin
index 438abe4..4434477 100644
--- a/nikola/plugins/compile/rest/chart.plugin
+++ b/nikola/plugins/compile/rest/chart.plugin
@@ -4,11 +4,11 @@ module = chart
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Chart directive based in PyGal
diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py
index 88fdff3..17363cb 100644
--- a/nikola/plugins/compile/rest/chart.py
+++ b/nikola/plugins/compile/rest/chart.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -23,27 +23,22 @@
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
"""Chart directive for reSTructuredText."""
-from ast import literal_eval
-
from docutils import nodes
from docutils.parsers.rst import Directive, directives
+from nikola.plugin_categories import RestExtension
+
try:
import pygal
except ImportError:
- pygal = None # NOQA
-
-from nikola.plugin_categories import RestExtension
-from nikola.utils import req_missing
+ pygal = None
_site = None
class Plugin(RestExtension):
-
"""Plugin for chart role."""
name = "rest_chart"
@@ -53,11 +48,10 @@ class Plugin(RestExtension):
global _site
_site = self.site = site
directives.register_directive('chart', Chart)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
class Chart(Directive):
-
"""reStructuredText extension for inserting charts as SVG.
Usage:
@@ -74,52 +68,69 @@ class Chart(Directive):
has_content = True
required_arguments = 1
option_spec = {
- "copy": directives.unchanged,
+ "box_mode": directives.unchanged,
+ "classes": directives.unchanged,
"css": directives.unchanged,
+ "defs": directives.unchanged,
+ "data_file": directives.unchanged,
"disable_xml_declaration": directives.unchanged,
"dots_size": directives.unchanged,
+ "dynamic_print_values": directives.unchanged,
"explicit_size": directives.unchanged,
"fill": directives.unchanged,
- "font_sizes": directives.unchanged,
+ "force_uri_protocol": directives.unchanged,
+ "half_pie": directives.unchanged,
"height": directives.unchanged,
"human_readable": directives.unchanged,
"include_x_axis": directives.unchanged,
+ "inner_radius": directives.unchanged,
"interpolate": directives.unchanged,
"interpolation_parameters": directives.unchanged,
"interpolation_precision": directives.unchanged,
+ "inverse_y_axis": directives.unchanged,
"js": directives.unchanged,
- "label_font_size": directives.unchanged,
"legend_at_bottom": directives.unchanged,
+ "legend_at_bottom_columns": directives.unchanged,
"legend_box_size": directives.unchanged,
- "legend_font_size": directives.unchanged,
"logarithmic": directives.unchanged,
- "major_label_font_size": directives.unchanged,
"margin": directives.unchanged,
- "no_data_font_size": directives.unchanged,
+ "margin_bottom": directives.unchanged,
+ "margin_left": directives.unchanged,
+ "margin_right": directives.unchanged,
+ "margin_top": directives.unchanged,
+ "max_scale": directives.unchanged,
+ "min_scale": directives.unchanged,
+ "missing_value_fill_truncation": directives.unchanged,
"no_data_text": directives.unchanged,
"no_prefix": directives.unchanged,
"order_min": directives.unchanged,
"pretty_print": directives.unchanged,
+ "print_labels": directives.unchanged,
"print_values": directives.unchanged,
+ "print_values_position": directives.unchanged,
"print_zeroes": directives.unchanged,
"range": directives.unchanged,
"rounded_bars": directives.unchanged,
+ "secondary_range": directives.unchanged,
"show_dots": directives.unchanged,
"show_legend": directives.unchanged,
"show_minor_x_labels": directives.unchanged,
+ "show_minor_y_labels": directives.unchanged,
+ "show_only_major_dots": directives.unchanged,
+ "show_x_guides": directives.unchanged,
+ "show_x_labels": directives.unchanged,
+ "show_y_guides": directives.unchanged,
"show_y_labels": directives.unchanged,
"spacing": directives.unchanged,
+ "stack_from_top": directives.unchanged,
"strict": directives.unchanged,
"stroke": directives.unchanged,
+ "stroke_style": directives.unchanged,
"style": directives.unchanged,
"title": directives.unchanged,
- "title_font_size": directives.unchanged,
- "to_dict": directives.unchanged,
"tooltip_border_radius": directives.unchanged,
- "tooltip_font_size": directives.unchanged,
"truncate_label": directives.unchanged,
"truncate_legend": directives.unchanged,
- "value_font_size": directives.unchanged,
"value_formatter": directives.unchanged,
"width": directives.unchanged,
"x_label_rotation": directives.unchanged,
@@ -128,37 +139,23 @@ class Chart(Directive):
"x_labels_major_count": directives.unchanged,
"x_labels_major_every": directives.unchanged,
"x_title": directives.unchanged,
+ "x_value_formatter": directives.unchanged,
+ "xrange": directives.unchanged,
"y_label_rotation": directives.unchanged,
"y_labels": directives.unchanged,
+ "y_labels_major": directives.unchanged,
+ "y_labels_major_count": directives.unchanged,
+ "y_labels_major_every": directives.unchanged,
"y_title": directives.unchanged,
"zero": directives.unchanged,
}
def run(self):
"""Run the directive."""
- if pygal is None:
- msg = req_missing(['pygal'], 'use the Chart directive', optional=True)
- return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')]
- options = {}
- if 'style' in self.options:
- style_name = self.options.pop('style')
- else:
- style_name = 'BlueStyle'
- if '(' in style_name: # Parametric style
- style = eval('pygal.style.' + style_name)
- else:
- style = getattr(pygal.style, style_name)
- for k, v in self.options.items():
- options[k] = literal_eval(v)
-
- chart = getattr(pygal, self.arguments[0])(style=style)
- chart.config(**options)
- for line in self.content:
- label, series = literal_eval('({0})'.format(line))
- chart.add(label, series)
- data = chart.render().decode('utf8')
- if _site and _site.invariant:
- import re
- data = re.sub('id="chart-[a-f0-9\-]+"', 'id="chart-foobar"', data)
- data = re.sub('#chart-[a-f0-9\-]+', '#chart-foobar', data)
- return [nodes.raw('', data, format='html')]
+ self.options['site'] = None
+ html = _site.plugin_manager.getPluginByName(
+ 'chart', 'ShortcodePlugin').plugin_object.handler(
+ self.arguments[0],
+ data='\n'.join(self.content),
+ **self.options)
+ return [nodes.raw('', html, format='html')]
diff --git a/nikola/plugins/compile/rest/doc.plugin b/nikola/plugins/compile/rest/doc.plugin
index facdd03..3b5c9c7 100644
--- a/nikola/plugins/compile/rest/doc.plugin
+++ b/nikola/plugins/compile/rest/doc.plugin
@@ -4,11 +4,11 @@ module = doc
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Manuel Kaufmann
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Role to link another page / post from the blog
diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py
index 99cce81..705c0bc 100644
--- a/nikola/plugins/compile/rest/doc.py
+++ b/nikola/plugins/compile/rest/doc.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -29,12 +29,11 @@
from docutils import nodes
from docutils.parsers.rst import roles
-from nikola.utils import split_explicit_title
+from nikola.utils import split_explicit_title, LOGGER, slugify
from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for doc role."""
name = 'rest_doc'
@@ -43,16 +42,13 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
roles.register_canonical_role('doc', doc_role)
+ self.site.register_shortcode('doc', doc_shortcode)
doc_role.site = site
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
-def doc_role(name, rawtext, text, lineno, inliner,
- options={}, content=[]):
- """Handle the doc role."""
- # split link's text and post's slug in role content
- has_explicit_title, title, slug = split_explicit_title(text)
- # check if the slug given is part of our blog posts/pages
+def _find_post(slug):
+ """Find a post with the given slug in posts or pages."""
twin_slugs = False
post = None
for p in doc_role.site.timeline:
@@ -62,27 +58,72 @@ def doc_role(name, rawtext, text, lineno, inliner,
else:
twin_slugs = True
break
+ return post, twin_slugs
+
+
+def _doc_link(rawtext, text, options={}, content=[]):
+ """Handle the doc role."""
+ # split link's text and post's slug in role content
+ has_explicit_title, title, slug = split_explicit_title(text)
+ if '#' in slug:
+ slug, fragment = slug.split('#', 1)
+ else:
+ fragment = None
+
+ # Look for the unslugified input first, then try to slugify (Issue #3450)
+ post, twin_slugs = _find_post(slug)
+ if post is None:
+ slug = slugify(slug)
+ post, twin_slugs = _find_post(slug)
try:
if post is None:
- raise ValueError
+ raise ValueError("No post with matching slug found.")
except ValueError:
+ return False, False, None, None, slug
+
+ if not has_explicit_title:
+ # use post's title as link's text
+ title = post.title()
+ permalink = post.permalink()
+ if fragment:
+ permalink += '#' + fragment
+
+ return True, twin_slugs, title, permalink, slug
+
+
+def doc_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ """Handle the doc role."""
+ success, twin_slugs, title, permalink, slug = _doc_link(rawtext, text, options, content)
+ if success:
+ if twin_slugs:
+ inliner.reporter.warning(
+ 'More than one post with the same slug. Using "{0}"'.format(permalink))
+ LOGGER.warning(
+ 'More than one post with the same slug. Using "{0}" for doc role'.format(permalink))
+ node = make_link_node(rawtext, title, permalink, options)
+ return [node], []
+ else:
msg = inliner.reporter.error(
'"{0}" slug doesn\'t exist.'.format(slug),
line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
- if not has_explicit_title:
- # use post's title as link's text
- title = post.title()
- permalink = post.permalink()
- if twin_slugs:
- msg = inliner.reporter.warning(
- 'More than one post with the same slug. Using "{0}"'.format(permalink))
- node = make_link_node(rawtext, title, permalink, options)
- return [node], []
+def doc_shortcode(*args, **kwargs):
+ """Implement the doc shortcode."""
+ text = kwargs['data']
+ success, twin_slugs, title, permalink, slug = _doc_link(text, text, LOGGER)
+ if success:
+ if twin_slugs:
+ LOGGER.warning(
+ 'More than one post with the same slug. Using "{0}" for doc shortcode'.format(permalink))
+ return '<a href="{0}">{1}</a>'.format(permalink, title)
+ else:
+ LOGGER.error(
+ '"{0}" slug doesn\'t exist.'.format(slug))
+ return '<span class="error text-error" style="color: red;">Invalid link: {0}</span>'.format(text)
def make_link_node(rawtext, text, url, options):
diff --git a/nikola/plugins/compile/rest/gist.plugin b/nikola/plugins/compile/rest/gist.plugin
index 9fa2e82..4a8a3a7 100644
--- a/nikola/plugins/compile/rest/gist.plugin
+++ b/nikola/plugins/compile/rest/gist.plugin
@@ -4,11 +4,11 @@ module = gist
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Gist directive
diff --git a/nikola/plugins/compile/rest/gist.py b/nikola/plugins/compile/rest/gist.py
index 736ee37..08aa46d 100644
--- a/nikola/plugins/compile/rest/gist.py
+++ b/nikola/plugins/compile/rest/gist.py
@@ -11,7 +11,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for gist directive."""
name = "rest_gist"
@@ -20,11 +19,10 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
directives.register_directive('gist', GitHubGist)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
class GitHubGist(Directive):
-
"""Embed GitHub Gist.
Usage:
diff --git a/nikola/plugins/compile/rest/listing.plugin b/nikola/plugins/compile/rest/listing.plugin
index 85c780f..5239f92 100644
--- a/nikola/plugins/compile/rest/listing.plugin
+++ b/nikola/plugins/compile/rest/listing.plugin
@@ -4,11 +4,11 @@ module = listing
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Extension for source listings
diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py
index 4871bf3..e5a73fa 100644
--- a/nikola/plugins/compile/rest/listing.py
+++ b/nikola/plugins/compile/rest/listing.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -28,26 +28,21 @@
"""Define and register a listing directive using the existing CodeBlock."""
-from __future__ import unicode_literals
import io
import os
import uuid
-try:
- from urlparse import urlunsplit
-except ImportError:
- from urllib.parse import urlunsplit # NOQA
+from urllib.parse import urlunsplit
import docutils.parsers.rst.directives.body
import docutils.parsers.rst.directives.misc
+import pygments
+import pygments.util
from docutils import core
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from docutils.parsers.rst.roles import set_classes
from docutils.parsers.rst.directives.misc import Include
-
from pygments.lexers import get_lexer_by_name
-import pygments
-import pygments.util
from nikola import utils
from nikola.plugin_categories import RestExtension
@@ -55,7 +50,6 @@ from nikola.plugin_categories import RestExtension
# A sanitized version of docutils.parsers.rst.directives.body.CodeBlock.
class CodeBlock(Directive):
-
"""Parse and mark up content of a code block."""
optional_arguments = 1
@@ -120,13 +114,13 @@ class CodeBlock(Directive):
return [node]
+
# Monkey-patch: replace insane docutils CodeBlock with our implementation.
docutils.parsers.rst.directives.body.CodeBlock = CodeBlock
docutils.parsers.rst.directives.misc.CodeBlock = CodeBlock
class Plugin(RestExtension):
-
"""Plugin for listing directive."""
name = "rest_listing"
@@ -138,12 +132,13 @@ class Plugin(RestExtension):
# leaving these to make the code directive work with
# docutils < 0.9
CodeBlock.site = site
+ Listing.site = site
directives.register_directive('code', CodeBlock)
directives.register_directive('code-block', CodeBlock)
directives.register_directive('sourcecode', CodeBlock)
directives.register_directive('listing', Listing)
Listing.folders = site.config['LISTINGS_FOLDERS']
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
# Add sphinx compatibility option
@@ -152,7 +147,6 @@ listing_spec['linenos'] = directives.unchanged
class Listing(Include):
-
"""Create a highlighted block of code from a file in listings/.
Usage:
@@ -171,7 +165,12 @@ class Listing(Include):
"""Run listing directive."""
_fname = self.arguments.pop(0)
fname = _fname.replace('/', os.sep)
- lang = self.arguments.pop(0)
+ try:
+ lang = self.arguments.pop(0)
+ self.options['code'] = lang
+ except IndexError:
+ self.options['literal'] = True
+
if len(self.folders) == 1:
listings_folder = next(iter(self.folders.keys()))
if fname.startswith(listings_folder):
@@ -181,22 +180,27 @@ class Listing(Include):
else:
fpath = os.path.join(fname) # must be new syntax: specify folder name
self.arguments.insert(0, fpath)
- self.options['code'] = lang
if 'linenos' in self.options:
self.options['number-lines'] = self.options['linenos']
- with io.open(fpath, 'r+', encoding='utf8') as fileobject:
+ with io.open(fpath, 'r+', encoding='utf-8-sig') as fileobject:
self.content = fileobject.read().splitlines()
self.state.document.settings.record_dependencies.add(fpath)
target = urlunsplit(("link", 'listing', fpath.replace('\\', '/'), '', ''))
+ src_target = urlunsplit(("link", 'listing_source', fpath.replace('\\', '/'), '', ''))
+ src_label = self.site.MESSAGES('Source')
generated_nodes = (
- [core.publish_doctree('`{0} <{1}>`_'.format(_fname, target))[0]])
+ [core.publish_doctree('`{0} <{1}>`_ `({2}) <{3}>`_' .format(
+ _fname, target, src_label, src_target))[0]])
generated_nodes += self.get_code_from_file(fileobject)
return generated_nodes
def get_code_from_file(self, data):
"""Create CodeBlock nodes from file object content."""
- return super(Listing, self).run()
+ return super().run()
def assert_has_content(self):
- """Listing has no content, override check from superclass."""
+ """Override check from superclass with nothing.
+
+ Listing has no content, override check from superclass.
+ """
pass
diff --git a/nikola/plugins/compile/rest/media.plugin b/nikola/plugins/compile/rest/media.plugin
index 9803c8f..396c2f9 100644
--- a/nikola/plugins/compile/rest/media.plugin
+++ b/nikola/plugins/compile/rest/media.plugin
@@ -4,11 +4,11 @@ module = media
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Directive to support oembed via micawber
diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py
index 345e331..d29d0a2 100644
--- a/nikola/plugins/compile/rest/media.py
+++ b/nikola/plugins/compile/rest/media.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -29,18 +29,16 @@
from docutils import nodes
from docutils.parsers.rst import Directive, directives
+from nikola.plugin_categories import RestExtension
+from nikola.utils import req_missing
+
try:
import micawber
except ImportError:
- micawber = None # NOQA
-
-
-from nikola.plugin_categories import RestExtension
-from nikola.utils import req_missing
+ micawber = None
class Plugin(RestExtension):
-
"""Plugin for reST media directive."""
name = "rest_media"
@@ -49,11 +47,11 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
directives.register_directive('media', Media)
- return super(Plugin, self).set_site(site)
+ self.site.register_shortcode('media', _gen_media_embed)
+ return super().set_site(site)
class Media(Directive):
-
"""reST extension for inserting any sort of media using micawber."""
has_content = False
@@ -62,9 +60,13 @@ class Media(Directive):
def run(self):
"""Run media directive."""
- if micawber is None:
- msg = req_missing(['micawber'], 'use the media directive', optional=True)
- return [nodes.raw('', '<div class="text-error">{0}</div>'.format(msg), format='html')]
+ html = _gen_media_embed(" ".join(self.arguments))
+ return [nodes.raw('', html, format='html')]
+
- providers = micawber.bootstrap_basic()
- return [nodes.raw('', micawber.parse_text(" ".join(self.arguments), providers), format='html')]
+def _gen_media_embed(url, *q, **kw):
+ if micawber is None:
+ msg = req_missing(['micawber'], 'use the media directive', optional=True)
+ return '<div class="text-error">{0}</div>'.format(msg)
+ providers = micawber.bootstrap_basic()
+ return micawber.parse_text(url, providers)
diff --git a/nikola/plugins/compile/rest/post_list.plugin b/nikola/plugins/compile/rest/post_list.plugin
index 48969bf..68abaef 100644
--- a/nikola/plugins/compile/rest/post_list.plugin
+++ b/nikola/plugins/compile/rest/post_list.plugin
@@ -4,11 +4,11 @@ module = post_list
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Udo Spallek
-version = 0.1
-website = http://getnikola.com
-description = Includes a list of posts with tag and slide based filters.
+version = 0.2
+website = https://getnikola.com/
+description = Includes a list of posts with tag and slice based filters.
diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py
index a22ee85..f7e95ed 100644
--- a/nikola/plugins/compile/rest/post_list.py
+++ b/nikola/plugins/compile/rest/post_list.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2013-2015 Udo Spallek, Roberto Alsina and others.
+# Copyright © 2013-2020 Udo Spallek, Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -23,15 +23,8 @@
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
"""Post list directive for reStructuredText."""
-from __future__ import unicode_literals
-
-import os
-import uuid
-import natsort
-
from docutils import nodes
from docutils.parsers.rst import Directive, directives
@@ -43,7 +36,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for reST post-list directive."""
name = "rest_post_list"
@@ -51,74 +43,14 @@ class Plugin(RestExtension):
def set_site(self, site):
"""Set Nikola site."""
self.site = site
- directives.register_directive('post-list', PostList)
- PostList.site = site
- return super(Plugin, self).set_site(site)
-
-
-class PostList(Directive):
-
- """Provide a reStructuredText directive to create a list of posts.
-
- Post List
- =========
- :Directive Arguments: None.
- :Directive Options: lang, start, stop, reverse, sort, tags, categories, slugs, all, template, id
- :Directive Content: None.
-
- The posts appearing in the list can be filtered by options.
- *List slicing* is provided with the *start*, *stop* and *reverse* options.
-
- The following not required options are recognized:
-
- ``start`` : integer
- The index of the first post to show.
- A negative value like ``-3`` will show the *last* three posts in the
- post-list.
- Defaults to None.
-
- ``stop`` : integer
- The index of the last post to show.
- A value negative value like ``-1`` will show every post, but not the
- *last* in the post-list.
- Defaults to None.
-
- ``reverse`` : flag
- Reverse the order of the post-list.
- Defaults is to not reverse the order of posts.
-
- ``sort``: string
- Sort post list by one of each post's attributes, usually ``title`` or a
- custom ``priority``. Defaults to None (chronological sorting).
-
- ``tags`` : string [, string...]
- Filter posts to show only posts having at least one of the ``tags``.
- Defaults to None.
-
- ``categories`` : string [, string...]
- Filter posts to show only posts having one of the ``categories``.
- Defaults to None.
+ directives.register_directive('post-list', PostListDirective)
+ directives.register_directive('post_list', PostListDirective)
+ PostListDirective.site = site
+ return super().set_site(site)
- ``slugs`` : string [, string...]
- Filter posts to show only posts having at least one of the ``slugs``.
- Defaults to None.
- ``all`` : flag
- Shows all posts and pages in the post list.
- Defaults to show only posts with set *use_in_feeds*.
-
- ``lang`` : string
- The language of post *titles* and *links*.
- Defaults to default language.
-
- ``template`` : string
- The name of an alternative template to render the post-list.
- Defaults to ``post_list_directive.tmpl``
-
- ``id`` : string
- A manual id for the post list.
- Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.
- """
+class PostListDirective(Directive):
+ """Provide a reStructuredText directive to create a list of posts."""
option_spec = {
'start': int,
@@ -126,12 +58,16 @@ class PostList(Directive):
'reverse': directives.flag,
'sort': directives.unchanged,
'tags': directives.unchanged,
+ 'require_all_tags': directives.flag,
'categories': directives.unchanged,
+ 'sections': directives.unchanged,
'slugs': directives.unchanged,
- 'all': directives.flag,
+ 'post_type': directives.unchanged,
+ 'type': directives.unchanged,
'lang': directives.unchanged,
'template': directives.path,
'id': directives.unchanged,
+ 'date': directives.unchanged,
}
def run(self):
@@ -140,73 +76,42 @@ class PostList(Directive):
stop = self.options.get('stop')
reverse = self.options.get('reverse', False)
tags = self.options.get('tags')
- tags = [t.strip().lower() for t in tags.split(',')] if tags else []
+ require_all_tags = 'require_all_tags' in self.options
categories = self.options.get('categories')
- categories = [c.strip().lower() for c in categories.split(',')] if categories else []
+ sections = self.options.get('sections')
slugs = self.options.get('slugs')
- slugs = [s.strip() for s in slugs.split(',')] if slugs else []
- show_all = self.options.get('all', False)
+ post_type = self.options.get('post_type')
+ type = self.options.get('type', False)
lang = self.options.get('lang', utils.LocaleBorg().current_lang)
template = self.options.get('template', 'post_list_directive.tmpl')
sort = self.options.get('sort')
- if self.site.invariant: # for testing purposes
- post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid')
- else:
- post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)
-
- filtered_timeline = []
- posts = []
- step = -1 if reverse is None else None
- if show_all is None:
- timeline = [p for p in self.site.timeline]
+ date = self.options.get('date')
+ filename = self.state.document.settings._nikola_source_path
+
+ output, deps = self.site.plugin_manager.getPluginByName(
+ 'post_list', 'ShortcodePlugin').plugin_object.handler(
+ start,
+ stop,
+ reverse,
+ tags,
+ require_all_tags,
+ categories,
+ sections,
+ slugs,
+ post_type,
+ type,
+ lang,
+ template,
+ sort,
+ state=self.state,
+ site=self.site,
+ date=date,
+ filename=filename)
+ self.state.document.settings.record_dependencies.add(
+ "####MAGIC####TIMELINE")
+ for d in deps:
+ self.state.document.settings.record_dependencies.add(d)
+ if output:
+ return [nodes.raw('', output, format='html')]
else:
- timeline = [p for p in self.site.timeline if p.use_in_feeds]
-
- if categories:
- timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories]
-
- for post in timeline:
- if tags:
- cont = True
- tags_lower = [t.lower() for t in post.tags]
- for tag in tags:
- if tag in tags_lower:
- cont = False
-
- if cont:
- continue
-
- filtered_timeline.append(post)
-
- if sort:
- filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC)
-
- for post in filtered_timeline[start:stop:step]:
- if slugs:
- cont = True
- for slug in slugs:
- if slug == post.meta('slug'):
- cont = False
-
- if cont:
- continue
-
- bp = post.translated_base_path(lang)
- if os.path.exists(bp):
- self.state.document.settings.record_dependencies.add(bp)
-
- posts += [post]
-
- if not posts:
return []
- self.state.document.settings.record_dependencies.add("####MAGIC####TIMELINE")
-
- template_data = {
- 'lang': lang,
- 'posts': posts,
- 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),
- 'post_list_id': post_list_id,
- }
- output = self.site.template_system.render_template(
- template, None, template_data)
- return [nodes.raw('', output, format='html')]
diff --git a/nikola/plugins/compile/rest/slides.plugin b/nikola/plugins/compile/rest/slides.plugin
deleted file mode 100644
index 5c05b89..0000000
--- a/nikola/plugins/compile/rest/slides.plugin
+++ /dev/null
@@ -1,14 +0,0 @@
-[Core]
-name = rest_slides
-module = slides
-
-[Nikola]
-compiler = rest
-plugincategory = CompilerExtension
-
-[Documentation]
-author = Roberto Alsina
-version = 0.1
-website = http://getnikola.com
-description = Slides directive
-
diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py
deleted file mode 100644
index 2522e55..0000000
--- a/nikola/plugins/compile/rest/slides.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2015 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Slides directive for reStructuredText."""
-
-from __future__ import unicode_literals
-
-import uuid
-
-from docutils import nodes
-from docutils.parsers.rst import Directive, directives
-
-from nikola.plugin_categories import RestExtension
-
-
-class Plugin(RestExtension):
-
- """Plugin for reST slides directive."""
-
- name = "rest_slides"
-
- def set_site(self, site):
- """Set Nikola site."""
- self.site = site
- directives.register_directive('slides', Slides)
- Slides.site = site
- return super(Plugin, self).set_site(site)
-
-
-class Slides(Directive):
-
- """reST extension for inserting slideshows."""
-
- has_content = True
-
- def run(self):
- """Run the slides directive."""
- if len(self.content) == 0: # pragma: no cover
- return
-
- if self.site.invariant: # for testing purposes
- carousel_id = 'slides_' + 'fixedvaluethatisnotauuid'
- else:
- carousel_id = 'slides_' + uuid.uuid4().hex
-
- output = self.site.template_system.render_template(
- 'slides.tmpl',
- None,
- {
- 'slides_content': self.content,
- 'carousel_id': carousel_id,
- }
- )
- return [nodes.raw('', output, format='html')]
-
-
-directives.register_directive('slides', Slides)
diff --git a/nikola/plugins/compile/rest/soundcloud.plugin b/nikola/plugins/compile/rest/soundcloud.plugin
index 75469e4..f85a964 100644
--- a/nikola/plugins/compile/rest/soundcloud.plugin
+++ b/nikola/plugins/compile/rest/soundcloud.plugin
@@ -4,11 +4,11 @@ module = soundcloud
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Soundcloud directive
diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py
index 30134a9..5dbcfc3 100644
--- a/nikola/plugins/compile/rest/soundcloud.py
+++ b/nikola/plugins/compile/rest/soundcloud.py
@@ -1,16 +1,39 @@
# -*- coding: utf-8 -*-
+# Copyright © 2012-2020 Roberto Alsina and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
"""SoundCloud directive for reStructuredText."""
from docutils import nodes
from docutils.parsers.rst import Directive, directives
-
+from nikola.plugins.compile.rest import _align_choice, _align_options_base
from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for soundclound directive."""
name = "rest_soundcloud"
@@ -20,18 +43,19 @@ class Plugin(RestExtension):
self.site = site
directives.register_directive('soundcloud', SoundCloud)
directives.register_directive('soundcloud_playlist', SoundCloudPlaylist)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
-CODE = ("""<iframe width="{width}" height="{height}"
+CODE = """\
+<div class="soundcloud-player{align}">
+<iframe width="{width}" height="{height}"
scrolling="no" frameborder="no"
-src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/{preslug}/"""
- """{sid}">
-</iframe>""")
+src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/{preslug}/{sid}">
+</iframe>
+</div>"""
class SoundCloud(Directive):
-
"""reST extension for inserting SoundCloud embedded music.
Usage:
@@ -46,6 +70,7 @@ class SoundCloud(Directive):
option_spec = {
'width': directives.positive_int,
'height': directives.positive_int,
+ "align": _align_choice
}
preslug = "tracks"
@@ -59,6 +84,10 @@ class SoundCloud(Directive):
'preslug': self.preslug,
}
options.update(self.options)
+ if self.options.get('align') in _align_options_base:
+ options['align'] = ' align-' + self.options['align']
+ else:
+ options['align'] = ''
return [nodes.raw('', CODE.format(**options), format='html')]
def check_content(self):
@@ -70,7 +99,6 @@ class SoundCloud(Directive):
class SoundCloudPlaylist(SoundCloud):
-
"""reST directive for SoundCloud playlists."""
preslug = "playlists"
diff --git a/nikola/plugins/compile/rest/thumbnail.plugin b/nikola/plugins/compile/rest/thumbnail.plugin
index 0084310..e7b649d 100644
--- a/nikola/plugins/compile/rest/thumbnail.plugin
+++ b/nikola/plugins/compile/rest/thumbnail.plugin
@@ -4,11 +4,11 @@ module = thumbnail
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
author = Pelle Nilsson
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = reST directive to facilitate enlargeable images with thumbnails
diff --git a/nikola/plugins/compile/rest/thumbnail.py b/nikola/plugins/compile/rest/thumbnail.py
index 1fae06c..06ca9e4 100644
--- a/nikola/plugins/compile/rest/thumbnail.py
+++ b/nikola/plugins/compile/rest/thumbnail.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2014-2015 Pelle Nilsson and others.
+# Copyright © 2014-2020 Pelle Nilsson and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -35,7 +35,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for thumbnail directive."""
name = "rest_thumbnail"
@@ -44,11 +43,10 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
directives.register_directive('thumbnail', Thumbnail)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
class Thumbnail(Figure):
-
"""Thumbnail directive for reST."""
def align(argument):
@@ -70,8 +68,12 @@ class Thumbnail(Figure):
def run(self):
"""Run the thumbnail directive."""
uri = directives.uri(self.arguments[0])
+ if uri.endswith('.svg'):
+ # the ? at the end makes docutil output an <img> instead of an object for the svg, which lightboxes may require
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri)) + '?'
+ else:
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
self.options['target'] = uri
- self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
if self.content:
(node,) = Figure.run(self)
else:
diff --git a/nikola/plugins/compile/rest/vimeo.plugin b/nikola/plugins/compile/rest/vimeo.plugin
index 688f981..89b171b 100644
--- a/nikola/plugins/compile/rest/vimeo.plugin
+++ b/nikola/plugins/compile/rest/vimeo.plugin
@@ -4,7 +4,7 @@ module = vimeo
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
description = Vimeo directive
diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py
index c694a87..7047b03 100644
--- a/nikola/plugins/compile/rest/vimeo.py
+++ b/nikola/plugins/compile/rest/vimeo.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -26,18 +26,17 @@
"""Vimeo directive for reStructuredText."""
-from docutils import nodes
-from docutils.parsers.rst import Directive, directives
-
-import requests
import json
+import requests
+from docutils import nodes
+from docutils.parsers.rst import Directive, directives
from nikola.plugin_categories import RestExtension
+from nikola.plugins.compile.rest import _align_choice, _align_options_base
class Plugin(RestExtension):
-
"""Plugin for vimeo reST directive."""
name = "rest_vimeo"
@@ -46,13 +45,15 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
directives.register_directive('vimeo', Vimeo)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
-CODE = """<iframe src="//player.vimeo.com/video/{vimeo_id}"
+CODE = """<div class="vimeo-video{align}">
+<iframe src="https://player.vimeo.com/video/{vimeo_id}"
width="{width}" height="{height}"
frameborder="0" webkitAllowFullScreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowFullScreen="allowFullScreen">
</iframe>
+</div>
"""
VIDEO_DEFAULT_HEIGHT = 500
@@ -60,7 +61,6 @@ VIDEO_DEFAULT_WIDTH = 281
class Vimeo(Directive):
-
"""reST extension for inserting vimeo embedded videos.
Usage:
@@ -75,6 +75,7 @@ class Vimeo(Directive):
option_spec = {
"width": directives.positive_int,
"height": directives.positive_int,
+ "align": _align_choice
}
# set to False for not querying the vimeo api for size
@@ -94,6 +95,10 @@ class Vimeo(Directive):
return err
self.set_video_size()
options.update(self.options)
+ if self.options.get('align') in _align_options_base:
+ options['align'] = ' align-' + self.options['align']
+ else:
+ options['align'] = ''
return [nodes.raw('', CODE.format(**options), format='html')]
def check_modules(self):
@@ -109,7 +114,7 @@ class Vimeo(Directive):
if json: # we can attempt to retrieve video attributes from vimeo
try:
- url = ('//vimeo.com/api/v2/video/{0}'
+ url = ('https://vimeo.com/api/v2/video/{0}'
'.json'.format(self.arguments[0]))
data = requests.get(url).text
video_attributes = json.loads(data)[0]
diff --git a/nikola/plugins/compile/rest/youtube.plugin b/nikola/plugins/compile/rest/youtube.plugin
index 5fbd67b..d83d0f8 100644
--- a/nikola/plugins/compile/rest/youtube.plugin
+++ b/nikola/plugins/compile/rest/youtube.plugin
@@ -4,7 +4,7 @@ module = youtube
[Nikola]
compiler = rest
-plugincategory = CompilerExtension
+PluginCategory = CompilerExtension
[Documentation]
version = 0.1
diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py
index 6c5c211..d52ec64 100644
--- a/nikola/plugins/compile/rest/youtube.py
+++ b/nikola/plugins/compile/rest/youtube.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright © 2012-2015 Roberto Alsina and others.
+# Copyright © 2012-2020 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
@@ -29,12 +29,11 @@
from docutils import nodes
from docutils.parsers.rst import Directive, directives
-
+from nikola.plugins.compile.rest import _align_choice, _align_options_base
from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for the youtube directive."""
name = "rest_youtube"
@@ -43,18 +42,19 @@ class Plugin(RestExtension):
"""Set Nikola site."""
self.site = site
directives.register_directive('youtube', Youtube)
- return super(Plugin, self).set_site(site)
+ return super().set_site(site)
CODE = """\
-<iframe width="{width}"
-height="{height}"
-src="//www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
-></iframe>"""
+<div class="youtube-video{align}">
+<iframe width="{width}" height="{height}"
+src="https://www.youtube-nocookie.com/embed/{yid}?rel=0&wmode=transparent"
+frameborder="0" allow="encrypted-media" allowfullscreen
+></iframe>
+</div>"""
class Youtube(Directive):
-
"""reST extension for inserting youtube embedded videos.
Usage:
@@ -67,8 +67,9 @@ class Youtube(Directive):
has_content = True
required_arguments = 1
option_spec = {
- "width": directives.positive_int,
- "height": directives.positive_int,
+ "width": directives.unchanged,
+ "height": directives.unchanged,
+ "align": _align_choice
}
def run(self):
@@ -76,10 +77,14 @@ class Youtube(Directive):
self.check_content()
options = {
'yid': self.arguments[0],
- 'width': 425,
- 'height': 344,
+ 'width': 560,
+ 'height': 315,
}
- options.update(self.options)
+ options.update({k: v for k, v in self.options.items() if v})
+ if self.options.get('align') in _align_options_base:
+ options['align'] = ' align-' + self.options['align']
+ else:
+ options['align'] = ''
return [nodes.raw('', CODE.format(**options), format='html')]
def check_content(self):