Skip to content

Commit

Permalink
Simplify TOC nesting code, fix for #1061 (#1062)
Browse files Browse the repository at this point in the history
  • Loading branch information
mossr authored Nov 7, 2023
1 parent c055207 commit 78ec3c6
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 56 deletions.
72 changes: 22 additions & 50 deletions src/converter/html/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,84 +170,56 @@ function hfun_toc(params::Vector{String})::String
inner = ""
headers = filter(p -> min p.second[3] max, PAGE_HEADERS)
isempty(headers) && return ""
levels = [h[3] for (rs,h) headers]

# find index of the top-most ancestor of each family
top_lvl_ancestor_idx = Vector{Int}(undef, length(levels))
for (i, lvl) in enumerate(levels)
if i == 1
top_lvl_ancestor_idx[i] = 1
levels = [h[3] for (rs,h) headers]
baselvl = minimum(h[3] for h in values(headers))
curlvl = baselvl

new_levels = [1] # first level should be left-most aligned (i.e., start at 1)
curlvl = 1
for i in 2:length(levels)
if levels[i-1] < levels[i]
curlvl += 1
else
a = i
for ai in reverse(1:i-1)
if lvl > levels[ai]
a = ai
break
end
end
top_lvl_ancestor_idx[i] = a
curlvl = levels[i] == baselvl ? 1 : 2
end
push!(new_levels, curlvl)
end

# get all the levels of the members in a family
families = map(top_lvl_idx->levels[findall(top_lvl_ancestor_idx .== top_lvl_idx)], top_lvl_ancestor_idx)

# indicate the smallest level (that which will be the most left aligned)
top_most_lvl = minimum(levels[top_lvl_ancestor_idx])

# get offset of level relative to the left-most level (i.e., the min.)
ancestor_offset_relative_to_min = map(member->top_most_lvl - member[1], families)

# indicators if any members of the family should be nested with empty bullets
make_empty_nest = map(fam_diff->any(fam_diff .< 0), diff.(families))

baselvl = minimum(h[3] for h in values(headers)) - 1
curlvl = first(families)[1] - 1
open_lists = 0
curskip = 0

for (li, (rs, h)) enumerate(headers)
lvl = h[3]
sep = abs(lvl - curlvl)
skipped_lvl = sep [0, 1]
make_empty = make_empty_nest[li]
skip = skipped_lvl ? sep - 1 : 0
if skip != 0
curskip = skip
end
if lvl curlvl
skip = new_levels[li]
if skip curskip
# Close previous list item
inner *= "</li>"
# Close additional sublists for each level eliminated
close_length = make_empty ? curlvl - lvl : curlvl - lvl - skip
for i = fill(nothing, close_length)
for i = fill(nothing, curskip - skip)
inner *= "</ol></li>"
open_lists -= 1
end
# Reopen for this list item
inner *= "<li>"
elseif lvl > curlvl
else
# Open additional sublists for each level added
if make_empty
# hide marker for the empty nested sublists
for i = fill(nothing, skip)
inner *= "<ol><li style=\"list-style-type: none;\">"
end
end
for i = fill(nothing, lvl - curlvl - skip)
for i = fill(nothing, skip - curskip)
inner *= "<ol><li>"
open_lists += 1
end
end
inner *= html_ahref_key(rs, h[1])
curlvl = lvl + ancestor_offset_relative_to_min[li]
curlvl = lvl
curskip = skip
# At this point, number of sublists (<ol><li>) open equals curlvl
end
# Close remaining lists, as if going down to the base level
for i = fill(nothing, curlvl - baselvl + curskip + sum(ancestor_offset_relative_to_min))
for i = fill(nothing, open_lists)
inner *= "</li></ol>"
end
toc = "<div class=\"franklin-toc\">" * inner * "</div>"
end


"""
$(SIGNATURES)
Expand Down
103 changes: 97 additions & 6 deletions test/converter/md/markdown2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,8 @@ end
<li>
<a href="#top-most_ancestor_of_family_2">Top-most ancestor of family 2</a>
<ol>
<li style="list-style-type: none;">
<ol>
<li>
<a href="#should_be_empty_nested">should be empty nested</a>
</li>
</ol>
<li>
<a href="#should_be_empty_nested">should be empty nested</a>
</li>
<li>
<a href="#part_of_family_2">part of family 2</a>
Expand Down Expand Up @@ -142,3 +138,98 @@ end
<p>done.</p>
""")
end

@testset "TOC-3" begin
fs()
s = raw"""
@def fd_rpath = "pages/ff/aa.md"
@def mintoclevel = 1
@def maxtoclevel = 7
\toc
# H1
### H3
#### H4
## H2
## H2
##### H5
# H1
### H3
## H2
## H2
#### H4
# H1
#### H4
#### H4
###### H6
#### H4
#### H4
""" |> seval
@test isapproxstr(s, raw"""
<div class="franklin-toc">
<ol>
<li>
<a href="#h1">H1</a>
<ol>
<li>
<a href="#h3">H3</a>
<ol>
<li><a href="#h4">H4</a></li>
</ol>
</li>
<li><a href="#h2">H2</a></li>
<li>
<a href="#h2__2">H2</a>
<ol>
<li><a href="#h5">H5</a></li>
</ol>
</li>
</ol>
</li>
<li>
<a href="#h1__2">H1</a>
<ol>
<li><a href="#h3__2">H3</a></li>
<li><a href="#h2__3">H2</a></li>
<li>
<a href="#h2__4">H2</a>
<ol>
<li><a href="#h4__2">H4</a></li>
</ol>
</li>
</ol>
</li>
<li>
<a href="#h1__3">H1</a>
<ol>
<li><a href="#h4__3">H4</a></li>
<li>
<a href="#h4__4">H4</a>
<ol>
<li><a href="#h6">H6</a></li>
</ol>
</li>
<li><a href="#h4__5">H4</a></li>
<li><a href="#h4__6">H4</a></li>
</ol>
</li>
</ol>
</div>
<h1 id="h1"><a href="#h1" class="header-anchor">H1</a></h1>
<h3 id="h3"><a href="#h3" class="header-anchor">H3</a></h3>
<h4 id="h4"><a href="#h4" class="header-anchor">H4</a></h4>
<h2 id="h2"><a href="#h2" class="header-anchor">H2</a></h2>
<h2 id="h2__2"><a href="#h2__2" class="header-anchor">H2</a></h2>
<h5 id="h5"><a href="#h5" class="header-anchor">H5</a></h5>
<h1 id="h1__2"><a href="#h1__2" class="header-anchor">H1</a></h1>
<h3 id="h3__2"><a href="#h3__2" class="header-anchor">H3</a></h3>
<h2 id="h2__3"><a href="#h2__3" class="header-anchor">H2</a></h2>
<h2 id="h2__4"><a href="#h2__4" class="header-anchor">H2</a></h2>
<h4 id="h4__2"><a href="#h4__2" class="header-anchor">H4</a></h4>
<h1 id="h1__3"><a href="#h1__3" class="header-anchor">H1</a></h1>
<h4 id="h4__3"><a href="#h4__3" class="header-anchor">H4</a></h4>
<h4 id="h4__4"><a href="#h4__4" class="header-anchor">H4</a></h4>
<h6 id="h6"><a href="#h6" class="header-anchor">H6</a></h6>
<h4 id="h4__5"><a href="#h4__5" class="header-anchor">H4</a></h4>
<h4 id="h4__6"><a href="#h4__6" class="header-anchor">H4</a></h4>
""")
end

0 comments on commit 78ec3c6

Please sign in to comment.