make showing empty pages opt-in

This commit is contained in:
Antoine Vandevenne (anv) 2021-02-22 12:50:54 +01:00
parent 1af66f3b85
commit c259856d85
4 changed files with 63 additions and 53 deletions

View File

@ -1,5 +1,5 @@
:empty_page:
:show_content:
=================================
Contributing to the documentation

View File

@ -1,18 +1,14 @@
from . import pygments_override
from . import translator
import sphinx.builders.html
from docutils import nodes
from sphinx import addnodes
from sphinx.environment.adapters import toctree
from docutils import nodes
from . import pygments_override, translator
def setup(app):
app.set_translator('html', translator.BootstrapTranslator)
# VFE TODO check if default meta initialization is necessary.
# If not, remove update_meta method
app.connect('html-page-context', update_meta)
app.connect('html-page-context', set_missing_meta)
app.add_js_file('js/utils.js') # Keep in first position
app.add_js_file('js/layout.js')
@ -20,14 +16,12 @@ def setup(app):
app.add_js_file('js/page_toc.js')
def update_meta(app, pagename, templatename, context, doctree):
meta = context.get('meta')
if meta is None:
meta = context['meta'] = {}
# TODO VFE detailed explanation of the patch logic and use.
def set_missing_meta(app, pagename, templatename, context, doctree):
if context.get('meta') is None: # Pages without title (used with `include::`) have no meta
context['meta'] = {}
class Monkey(object):
""" Replace patched method of an object by a new method receiving the old one in argument. """
def __init__(self, obj):
self.obj = obj
def __call__(self, fn):
@ -37,40 +31,57 @@ class Monkey(object):
@Monkey(toctree.TocTree)
def resolve(old_resolve, tree, docname, *args, **kwargs):
def _clear_empty_pages_reference(_node) -> None:
""" Disable references to 'empty' toctree pages.
Inspect node's children to determine whether the page is a toc and, if so, clear its
reference URL. (<a href="#"/>)
If the page has the `show_content` metadata, don't clear the reference.
Internal structure of nodes:
<ul>
<li>
<p><a/></p>
<ul>
...
</ul>
</li>
<li/>
<ul/>
"""
if isinstance(_node, nodes.reference): # The node is a reference (<a/>)
_subnode_docname = _get_docname(_node)
if _subnode_docname and any(
isinstance(_subnode, nodes.bullet_list)
for _subnode in _node.parent.parent.children
): # The node references a toc
if 'show_content' not in tree.env.metadata[_subnode_docname]:
_node['refuri'] = '#' # The page must not be accessible
elif isinstance(_node, (addnodes.compact_paragraph, nodes.bullet_list, nodes.list_item)):
for _subnode in _node.children:
_clear_empty_pages_reference(_subnode)
def _get_docname(_node):
"""
docname = a/b/c/the_page_being_rendered
_ref = ../../contributing/documentation
_path_parts = ['..', '..', 'contributing', 'documentation']
_res = ['a', 'contributing', 'documentation']
_docname = a/contributing/documentation
"""
_ref = _node['refuri'].replace('.html', '')
_parent_directory_occurrences = _ref.count('..')
if not _parent_directory_occurrences: # The ref is already the docname
_docname = _ref
else:
_path_parts = _ref.split('/')
_res = docname.split('/')[:-(_parent_directory_occurrences+1)] \
+ _path_parts[_parent_directory_occurrences:]
_docname = '/'.join(_res)
return _docname
resolved_toc = old_resolve(tree, docname, *args, **kwargs)
if resolved_toc:
_toctree_add_empty_class(tree, resolved_toc, docname)
if resolved_toc: # `resolve` returns None if the depth of the TOC to resolve is too high
_clear_empty_pages_reference(resolved_toc)
return resolved_toc
def _toctree_add_empty_class(tree, node, docname) -> None:
for subnode in node.children:
if isinstance(subnode, (
addnodes.compact_paragraph,
nodes.list_item,
nodes.bullet_list
)):
# for <p>, <li> and <ul> just recurse
_toctree_add_empty_class(tree, subnode, docname)
elif isinstance(subnode, nodes.reference):
toc_ref = get_reference(subnode, docname)
if toc_ref and 'empty_page' in tree.env.metadata[toc_ref]:
subnode['classes'].append('o_empty_page')
subnode['refuri'] = '#' # The link must not be clickable
def get_reference(node, docname):
ref = node['refuri'].replace('.html', '') # applications.html
if ref.find('..') < 0:
# direct reference
return ref
splitted_refuri = ref.split('/')
count = 0 # Number of ../ in refuri
for split in splitted_refuri:
if split == "..":
count += 1
# ref = ../../../contributing/documentation
# docname = services/legal/terms/enterprise
# res = contributing/documentation
res = docname.split('/')[:-(count+1)] + splitted_refuri[count:]
return "/".join(
res
)

View File

@ -64,11 +64,11 @@
{% set main_classes = [] %}
{% if pagename == master_doc %} {# The current page is the homepage #}
{% set main_classes = main_classes + ['index'] %}
{% set main_classes = main_classes + ['index'] %} {# TODO ANVFE should be 'o_index' #}
{% endif %}
{% if 'code-column' in meta %} {# The page contains a 'memento' (side dynamic block) #}
{% set main_classes = main_classes + ['has_code_col'] %}
{% set main_classes = main_classes + ['has_code_col'] %} {# TODO ANVFE see #}
{% endif %}
{% if 'classes' in meta %} {# The page source defines custom classes #}

View File

@ -1,6 +1,5 @@
<div class="o_logo_wrapper">
<a href="{{ pathto(master_doc) }}" class="o_logo">
{# TODO EDI/design make one unique image for Odoo docs s.t. when clicking on docs you are also redirected #}
<img src="{{ pathto('_static/img/logos/odoo_logo.svg', 1) }}"
height="30" alt="Odoo"/>
<span class="text-dark fw_extralight">docs</span>