diff options
| author | 2021-02-03 19:17:50 -0500 | |
|---|---|---|
| committer | 2021-02-03 19:17:50 -0500 | |
| commit | 475d074fd74425efbe783fad08f97f2df0c4909f (patch) | |
| tree | 2acdae53999b3c74b716efa4edb5b40311fa356a /nikola/plugins/compile/rest | |
| parent | cd502d52787f666fff3254d7d7e7578930c813c2 (diff) | |
| parent | 3a0d66f07b112b6d2bdc2b57bbf717a89a351ce6 (diff) | |
Update upstream source from tag 'upstream/8.1.2'
Update to upstream version '8.1.2'
with Debian dir e5e966a9e6010ef70618dc9a61558fa4db35aceb
Diffstat (limited to 'nikola/plugins/compile/rest')
23 files changed, 309 insertions, 494 deletions
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py index b75849f..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-2016 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,28 +26,28 @@ """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, - LocaleBorg + LocaleBorg, + map_metadata ) @@ -58,15 +58,57 @@ class CompileRest(PageCompiler): friendly_name = "reStructuredText" demote_headers = True logger = None - - 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') @@ -76,38 +118,42 @@ class CompileRest(PageCompiler): 'stylesheet_path': None, 'link_stylesheet': True, 'syntax_highlight': 'short', - 'math_output': 'mathjax', + # 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') + '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'), } - output, error_level, deps = rst2html( - data, settings_overrides=settings_overrides, logger=self.logger, source_path=source_path, l_add_ln=add_ln, transforms=self.site.rst_transforms, - no_title_transform=self.site.config.get('NO_DOCUTILS_TITLE_TRANSFORM', False)) - if not isinstance(output, unicode_str): + 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: - try: - post = self.site.post_per_input_file[source] - except KeyError: - post = None - 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, shortcode_deps = self.site.apply_shortcodes(output, filename=source, with_dependencies=True, extra_context=dict(post=post)) + output, error_level, deps, shortcode_deps = self.compile_string(data, source, is_two_file, post, lang) out_file.write(output) if post is None: if deps.list: self.logger.error( - "Cannot save dependencies for post {0} due to unregistered source file name", + "Cannot save dependencies for post {0} (post unknown)", source) else: post._depfile[dest] += deps.list @@ -129,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): @@ -155,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) @@ -179,32 +229,32 @@ 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.no_title_transform = kwargs.pop('no_title_transform', False) + self.logging_settings = kwargs.pop('nikola_logging_settings', {}) docutils.readers.standalone.Reader.__init__(self, *args, **kwargs) def get_transforms(self): """Get docutils transforms.""" - transforms = docutils.readers.standalone.Reader(self).get_transforms() + self.transforms - if self.no_title_transform: - transforms = [t for t in transforms if str(t) != "<class 'docutils.transforms.frontmatter.DocTitle'>"] - return transforms + return docutils.readers.standalone.Reader(self).get_transforms() + self.transforms def new_document(self): """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=[]): - """A shortcode role that passes through raw inline HTML.""" + """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) @@ -226,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): @@ -245,18 +295,53 @@ 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(' ' * (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, - enable_exit_status=None, logger=None, l_add_ln=0, transforms=None, - no_title_transform=False): + 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. Dictionary keys are the names of parts, and values are Unicode strings; @@ -268,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, no_title_transform=no_title_transform) # 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, @@ -294,7 +381,8 @@ 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') @@ -302,3 +390,14 @@ _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 0a7896f..4434477 100644 --- a/nikola/plugins/compile/rest/chart.plugin +++ b/nikola/plugins/compile/rest/chart.plugin @@ -4,7 +4,7 @@ module = chart [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Roberto Alsina diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py index 24f459b..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-2016 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,21 +23,17 @@ # 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 @@ -52,8 +48,7 @@ class Plugin(RestExtension): global _site _site = self.site = site directives.register_directive('chart', Chart) - self.site.register_shortcode('chart', _gen_chart) - return super(Plugin, self).set_site(site) + return super().set_site(site) class Chart(Directive): @@ -77,6 +72,7 @@ class Chart(Directive): "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, @@ -157,41 +153,9 @@ class Chart(Directive): def run(self): """Run the directive.""" self.options['site'] = None - html = _gen_chart(self.arguments[0], data='\n'.join(self.content), **self.options) + 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')] - - -def _gen_chart(chart_type, **_options): - if pygal is None: - msg = req_missing(['pygal'], 'use the Chart directive', optional=True) - return '<div class="text-error">{0}</div>'.format(msg) - options = {} - data = _options.pop('data') - _options.pop('post', None) - _options.pop('site') - if 'style' in _options: - style_name = _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 _options.items(): - try: - options[k] = literal_eval(v) - except: - options[k] = v - chart = pygal - for o in chart_type.split('.'): - chart = getattr(chart, o) - chart = chart(style=style) - if _site and _site.invariant: - chart.no_prefix = True - chart.config(**options) - for line in data.splitlines(): - line = line.strip() - if line: - label, series = literal_eval('({0})'.format(line)) - chart.add(label, series) - return chart.render().decode('utf8') diff --git a/nikola/plugins/compile/rest/doc.plugin b/nikola/plugins/compile/rest/doc.plugin index e447eb2..3b5c9c7 100644 --- a/nikola/plugins/compile/rest/doc.plugin +++ b/nikola/plugins/compile/rest/doc.plugin @@ -4,7 +4,7 @@ module = doc [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Manuel Kaufmann diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py index 55f576d..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-2016 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,7 +29,7 @@ from docutils import nodes from docutils.parsers.rst import roles -from nikola.utils import split_explicit_title, LOGGER +from nikola.utils import split_explicit_title, LOGGER, slugify from nikola.plugin_categories import RestExtension @@ -44,14 +44,11 @@ class Plugin(RestExtension): 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_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) - # 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: @@ -61,10 +58,27 @@ def _doc_link(rawtext, text, options={}, content=[]): 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 @@ -72,6 +86,8 @@ def _doc_link(rawtext, text, options={}, content=[]): # 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 @@ -83,7 +99,7 @@ def doc_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if twin_slugs: inliner.reporter.warning( 'More than one post with the same slug. Using "{0}"'.format(permalink)) - LOGGER.warn( + 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], [] @@ -101,7 +117,7 @@ def doc_shortcode(*args, **kwargs): success, twin_slugs, title, permalink, slug = _doc_link(text, text, LOGGER) if success: if twin_slugs: - LOGGER.warn( + 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: diff --git a/nikola/plugins/compile/rest/gist.plugin b/nikola/plugins/compile/rest/gist.plugin index 763c1d2..4a8a3a7 100644 --- a/nikola/plugins/compile/rest/gist.plugin +++ b/nikola/plugins/compile/rest/gist.plugin @@ -4,7 +4,7 @@ module = gist [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Roberto Alsina diff --git a/nikola/plugins/compile/rest/gist.py b/nikola/plugins/compile/rest/gist.py index e40c3b2..08aa46d 100644 --- a/nikola/plugins/compile/rest/gist.py +++ b/nikola/plugins/compile/rest/gist.py @@ -19,7 +19,7 @@ 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): diff --git a/nikola/plugins/compile/rest/listing.plugin b/nikola/plugins/compile/rest/listing.plugin index 3ebb296..5239f92 100644 --- a/nikola/plugins/compile/rest/listing.plugin +++ b/nikola/plugins/compile/rest/listing.plugin @@ -4,7 +4,7 @@ module = listing [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Roberto Alsina diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py index 4dfbedc..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-2016 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 @@ -119,6 +114,7 @@ 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 @@ -142,7 +138,7 @@ class Plugin(RestExtension): 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 @@ -186,7 +182,7 @@ class Listing(Include): self.arguments.insert(0, fpath) 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('\\', '/'), '', '')) @@ -200,8 +196,11 @@ class Listing(Include): 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 8dfb19c..396c2f9 100644 --- a/nikola/plugins/compile/rest/media.plugin +++ b/nikola/plugins/compile/rest/media.plugin @@ -4,7 +4,7 @@ module = media [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Roberto Alsina diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py index 8a69586..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-2016 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,14 +29,13 @@ 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): @@ -49,7 +48,7 @@ class Plugin(RestExtension): self.site = site directives.register_directive('media', Media) self.site.register_shortcode('media', _gen_media_embed) - return super(Plugin, self).set_site(site) + return super().set_site(site) class Media(Directive): diff --git a/nikola/plugins/compile/rest/post_list.plugin b/nikola/plugins/compile/rest/post_list.plugin index 1802f2b..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 +version = 0.2 website = https://getnikola.com/ -description = Includes a list of posts with tag and slide based filters. +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 8cfd5bf..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-2016 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,21 +23,13 @@ # 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 from nikola import utils from nikola.plugin_categories import RestExtension -from nikola.packages.datecond import date_in_range # WARNING: the directive name is post-list # (with a DASH instead of an UNDERSCORE) @@ -51,91 +43,14 @@ class Plugin(RestExtension): def set_site(self, site): """Set Nikola site.""" self.site = site - self.site.register_shortcode('post-list', _do_post_list) - 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, date, tags, categories, sections, slugs, post_type, 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). + directives.register_directive('post-list', PostListDirective) + directives.register_directive('post_list', PostListDirective) + PostListDirective.site = site + return super().set_site(site) - ``date`` : string - Show posts that match date range specified by this option. Format: - * comma-separated clauses (AND) - * clause: attribute comparison_operator value (spaces optional) - * attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime - * comparison_operator: == != <= >= < > - * value: integer or dateutil-compatible date input - - ``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. - - ``sections`` : string [, string...] - Filter posts to show only posts having one of the ``sections``. - Defaults to None. - - ``slugs`` : string [, string...] - Filter posts to show only posts having at least one of the ``slugs``. - Defaults to None. - - ``post_type`` (or ``type``) : string - Show only ``posts``, ``pages`` or ``all``. - Replaces ``all``. Defaults to ``posts``. - - ``all`` : flag - (deprecated, use ``post_type`` instead) - Shows all posts and pages in the post list. Defaults to show only posts. - - ``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, @@ -143,12 +58,12 @@ 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, 'post_type': directives.unchanged, 'type': directives.unchanged, - 'all': directives.flag, 'lang': directives.unchanged, 'template': directives.path, 'id': directives.unchanged, @@ -161,151 +76,42 @@ class PostList(Directive): stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') + require_all_tags = 'require_all_tags' in self.options categories = self.options.get('categories') sections = self.options.get('sections') slugs = self.options.get('slugs') post_type = self.options.get('post_type') type = self.options.get('type', False) - all = self.options.get('all', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') sort = self.options.get('sort') date = self.options.get('date') - - output, deps = _do_post_list(start, stop, reverse, tags, categories, sections, slugs, post_type, type, - all, lang, template, sort, state=self.state, site=self.site, date=date) - self.state.document.settings.record_dependencies.add("####MAGIC####TIMELINE") + 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: return [] - - -def _do_post_list(start=None, stop=None, reverse=False, tags=None, categories=None, - sections=None, slugs=None, post_type='post', type=False, all=False, - lang=None, template='post_list_directive.tmpl', sort=None, - id=None, data=None, state=None, site=None, date=None, filename=None, post=None): - if lang is None: - lang = utils.LocaleBorg().current_lang - if site.invariant: # for testing purposes - post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid' - else: - post_list_id = id or 'post_list_' + uuid.uuid4().hex - - # Get post from filename if available - if filename: - self_post = site.post_per_input_file.get(filename) - else: - self_post = None - - if self_post: - self_post.register_depfile("####MAGIC####TIMELINE", lang=lang) - - # If we get strings for start/stop, make them integers - if start is not None: - start = int(start) - if stop is not None: - stop = int(stop) - - # Parse tags/categories/sections/slugs (input is strings) - tags = [t.strip().lower() for t in tags.split(',')] if tags else [] - categories = [c.strip().lower() for c in categories.split(',')] if categories else [] - sections = [s.strip().lower() for s in sections.split(',')] if sections else [] - slugs = [s.strip() for s in slugs.split(',')] if slugs else [] - - filtered_timeline = [] - posts = [] - step = -1 if reverse is None else None - - if type is not False: - post_type = type - - # TODO: remove in v8 - if all is not False: - timeline = [p for p in site.timeline] - elif post_type == 'page' or post_type == 'pages': - timeline = [p for p in site.timeline if not p.use_in_feeds] - elif post_type == 'all': - timeline = [p for p in site.timeline] - else: # post - timeline = [p for p in site.timeline if p.use_in_feeds] - - # TODO: replaces all, uncomment in v8 - # if post_type == 'page' or post_type == 'pages': - # timeline = [p for p in site.timeline if not p.use_in_feeds] - # elif post_type == 'all': - # timeline = [p for p in site.timeline] - # else: # post - # timeline = [p for p in site.timeline if p.use_in_feeds] - - if categories: - timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories] - - if sections: - timeline = [p for p in timeline if p.section_name(lang).lower() in sections] - - 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) - - if date: - filtered_timeline = [p for p in filtered_timeline if date_in_range(date, p.date)] - - 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) and state: - state.document.settings.record_dependencies.add(bp) - elif os.path.exists(bp) and self_post: - self_post.register_depfile(bp, lang=lang) - - posts += [post] - - if not posts: - return '', [] - - template_deps = site.template_system.template_deps(template) - if state: - # Register template as a dependency (Issue #2391) - for d in template_deps: - state.document.settings.record_dependencies.add(d) - elif self_post: - for d in template_deps: - self_post.register_depfile(d, lang=lang) - - template_data = { - 'lang': lang, - 'posts': posts, - # Need to provide str, not TranslatableSetting (Issue #2104) - 'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang], - 'post_list_id': post_list_id, - 'messages': site.MESSAGES, - } - output = site.template_system.render_template( - template, None, template_data) - return output, template_deps - -# Request file name from shortcode (Issue #2412) -_do_post_list.nikola_shortcode_pass_filename = True diff --git a/nikola/plugins/compile/rest/slides.plugin b/nikola/plugins/compile/rest/slides.plugin deleted file mode 100644 index 389da39..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 = https://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 7c5b34b..0000000 --- a/nikola/plugins/compile/rest/slides.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright © 2012-2016 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 4e36ea4..f85a964 100644 --- a/nikola/plugins/compile/rest/soundcloud.plugin +++ b/nikola/plugins/compile/rest/soundcloud.plugin @@ -4,7 +4,7 @@ module = soundcloud [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Roberto Alsina diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py index 9fabe70..5dbcfc3 100644 --- a/nikola/plugins/compile/rest/soundcloud.py +++ b/nikola/plugins/compile/rest/soundcloud.py @@ -1,5 +1,29 @@ # -*- 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 @@ -19,7 +43,7 @@ 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 = """\ diff --git a/nikola/plugins/compile/rest/thumbnail.plugin b/nikola/plugins/compile/rest/thumbnail.plugin index 3324c31..e7b649d 100644 --- a/nikola/plugins/compile/rest/thumbnail.plugin +++ b/nikola/plugins/compile/rest/thumbnail.plugin @@ -4,7 +4,7 @@ module = thumbnail [Nikola] compiler = rest -plugincategory = CompilerExtension +PluginCategory = CompilerExtension [Documentation] author = Pelle Nilsson diff --git a/nikola/plugins/compile/rest/thumbnail.py b/nikola/plugins/compile/rest/thumbnail.py index 37e0973..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-2016 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 @@ -43,7 +43,7 @@ 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): @@ -69,7 +69,7 @@ class Thumbnail(Figure): """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 colorbox requires + # 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)) 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 f1ac6c3..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-2016 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,15 +26,14 @@ """Vimeo 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 - -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): @@ -46,7 +45,7 @@ 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 = """<div class="vimeo-video{align}"> 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 b3dde62..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-2016 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,8 +28,8 @@ from docutils import nodes from docutils.parsers.rst import Directive, directives -from nikola.plugins.compile.rest import _align_choice, _align_options_base +from nikola.plugins.compile.rest import _align_choice, _align_options_base from nikola.plugin_categories import RestExtension @@ -42,13 +42,14 @@ 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 = """\ <div class="youtube-video{align}"> <iframe width="{width}" height="{height}" -src="https://www.youtube.com/embed/{yid}?rel=0&hd=1&wmode=transparent" +src="https://www.youtube-nocookie.com/embed/{yid}?rel=0&wmode=transparent" +frameborder="0" allow="encrypted-media" allowfullscreen ></iframe> </div>""" @@ -66,8 +67,8 @@ 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 } @@ -76,10 +77,10 @@ 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: |
