Skip to content

Commit

Permalink
Merge pull request #107 from jbms/fix-hamburger-menu
Browse files Browse the repository at this point in the history
Fix hamburger menu and fix local/global toc split
  • Loading branch information
jbms authored Jun 1, 2022
2 parents c00d9df + 6d668ee commit e1c50aa
Showing 1 changed file with 60 additions and 22 deletions.
82 changes: 60 additions & 22 deletions sphinx_immaterial/nav_adapt.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@ class MkdocsNavEntry:
# List of children
children: List["MkdocsNavEntry"]
# Set to `True` if this page, or a descendent, is the current page.
# Excludes links to sections within in an active page.
active: bool
# Set to `True` if this page is the current page.
# Set to `True` if this page is the current page. Excludes links to
# sections within in an active page.
current: bool

# Set to `True` if `active`, or if this is a link to a section within an `active` page.
active_or_section_within_active: bool = False

# Set to `True` if this entry does not refer to a unique page but is merely
# a TOC caption.
caption_only: bool
Expand Down Expand Up @@ -96,8 +102,6 @@ def __init__(
self._rendered_title_text: Optional[str] = None
self._url: Optional[str] = None
self._builder = builder
# Indicates if this node or one of its descendents is the current page.
self._active = False
# List of direct children.
self._children: List[MkdocsNavEntry] = []

Expand Down Expand Up @@ -145,8 +149,6 @@ def visit_bullet_list(self, node: docutils.nodes.bullet_list):
title_text = self._render_title(self._prev_caption.children)
self._prev_caption = None
child_visitor = _TocVisitor(self.document, self._builder)
if node.get("iscurrent", False):
child_visitor._active = True
node.walk(child_visitor)
url = None
children = child_visitor._children
Expand All @@ -157,7 +159,7 @@ def visit_bullet_list(self, node: docutils.nodes.bullet_list):
title_text=title_text,
url=url,
children=children,
active=child_visitor._active,
active=False,
current=False,
caption_only=True,
)
Expand All @@ -170,17 +172,15 @@ def get_result(self) -> MkdocsNavEntry:
title_text=cast(str, self._rendered_title_text),
url=self._url,
children=self._children,
active=self._active,
current=self._active and self._url == "",
active=False,
current=False,
caption_only=False,
)

def visit_list_item(self, node: docutils.nodes.list_item):
# Child node. Collect its url, title, and any children using a separate
# `_TocVisitor`.
child_visitor = _TocVisitor(self.document, self._builder)
if node.get("iscurrent", False):
child_visitor._active = True
for child in node.children:
child.walk(child_visitor)
child_result = child_visitor.get_result()
Expand Down Expand Up @@ -336,14 +336,36 @@ def _get_current_page_in_toc(toc: List[MkdocsNavEntry]) -> Optional[MkdocsNavEnt
return None


def _collapse_children_not_on_same_page(entry: MkdocsNavEntry) -> MkdocsNavEntry:
def _prune_toc_by_active(
entry: MkdocsNavEntry, active: bool
) -> Optional[MkdocsNavEntry]:
"""Prunes entries from the TOC tree according to whether they are active.
Any TOC entries with a target on the current page (i.e. a section within the
current page) are marked active, while entries with a target on a different
page are not marked active.
:param entry: TOC root to recursively prune.
:param active: If `True`, prune targets not on the current page. If
`False`, prune targets on the current page, except if they transitively
contain children not in the current page.
:returns: Pruned copy of `entry`.
"""
if active and not entry.active_or_section_within_active:
return None

entry = copy.copy(entry)
if not entry.active:
entry.children = []
else:
entry.children = [
_collapse_children_not_on_same_page(child) for child in entry.children
]

new_children = []
for child in entry.children:
new_child = _prune_toc_by_active(child, active)
if new_child is not None:
new_children.append(new_child)
entry.children = new_children

if entry.active_or_section_within_active and not active and not entry.children:
return None

return entry


Expand Down Expand Up @@ -452,6 +474,7 @@ def _get_global_toc(app: sphinx.application.Sphinx, pagename: str, collapse: boo
real_page_url = builder.get_target_uri(pagename)

def _make_toc_for_page(key: TocEntryKey, children: List[MkdocsNavEntry]):
page_is_current = key in keys
children = list(children)
for i, child in enumerate(children):
child_key = key + (i,)
Expand All @@ -466,10 +489,15 @@ def _make_toc_for_page(key: TocEntryKey, children: List[MkdocsNavEntry]):
if uri.fragment:
child.url += f"#{uri.fragment}"
in_ancestors = child_key in ancestors
child_active = False
child_current = False
if in_ancestors:
child.active = True
child_active = True
if child_key in keys:
child.current = True
child_current = True
child.active = child_active and not page_is_current
child.current = child_current and not page_is_current
child.active_or_section_within_active = child_active
if in_ancestors or child.caption_only:
child.children = _make_toc_for_page(child_key, child.children)
else:
Expand All @@ -488,7 +516,7 @@ def _get_mkdocs_tocs(
pagename=pagename,
collapse=theme_options.get("globaltoc_collapse", False),
)
local_toc = []
local_toc: List[MkdocsNavEntry] = []
env = app.env
assert env is not None
builder = app.builder
Expand All @@ -497,9 +525,19 @@ def _get_mkdocs_tocs(
# Extract entry from `global_toc` corresponding to the current page.
current_page_toc_entry = _get_current_page_in_toc(global_toc)
if current_page_toc_entry:
local_toc = [_collapse_children_not_on_same_page(current_page_toc_entry)]
local_toc = cast(
List[MkdocsNavEntry],
[_prune_toc_by_active(current_page_toc_entry, active=True)],
)
if not duplicate_local_toc:
current_page_toc_entry.children = []
current_page_toc_entry.children = [
child
for child in [
_prune_toc_by_active(child, active=False)
for child in current_page_toc_entry.children
]
if child is not None
]

else:
# Every page is a child of the root page. We still want a full TOC
Expand Down

0 comments on commit e1c50aa

Please sign in to comment.