@@ -101,8 +101,8 @@ defmodule PardallMarkdown.Content.HtmlUtils do
101
101
def generate_anchors_and_toc ( html , % { slug: slug } ) do
102
102
{ updated_tree , % { toc: toc } } =
103
103
Floki . parse_fragment! ( html )
104
- |> Floki . traverse_and_update ( % { counters: % { } , toc: [ ] } , fn
105
- { "h" <> level , attrs , children } = el , acc ->
104
+ |> Floki . traverse_and_update ( % { counters: % { } , toc: [ ] , toc_positions: % { } } , fn
105
+ { "h" <> header_level , attrs , children } = el , acc ->
106
106
case find_node_text ( children ) do
107
107
nil ->
108
108
{ el , acc }
@@ -123,17 +123,23 @@ defmodule PardallMarkdown.Content.HtmlUtils do
123
123
{ "data-title" , title }
124
124
] , [ ] }
125
125
126
- toc_item = % {
126
+ int_header_level = parse_header_level ( header_level )
127
+ { :level , level , :positions , positions } =
128
+ get_toc_level ( acc . toc , int_header_level , acc . toc_positions )
129
+
130
+ link = % {
127
131
id: link_id ,
132
+ level: level ,
133
+ header: int_header_level ,
128
134
parent_slug: slug ,
129
- title: title ,
130
- level: get_level_for_toc ( acc [ :toc ] , level )
135
+ title: title
131
136
}
132
137
133
138
acc = put_in ( acc [ :counters ] [ id ] , increase_id_count ( count ) )
134
- acc = put_in ( acc [ :toc ] , acc . toc ++ [ toc_item ] )
139
+ acc = put_in ( acc [ :toc ] , acc . toc ++ [ link ] )
140
+ acc = put_in ( acc [ :toc_positions ] , positions )
135
141
136
- { { "h" <> level , attrs , [ anchor | children ] } , acc }
142
+ { { "h" <> header_level , attrs , [ anchor | children ] } , acc }
137
143
end
138
144
139
145
el , acc ->
@@ -143,8 +149,47 @@ defmodule PardallMarkdown.Content.HtmlUtils do
143
149
{ :ok , updated_tree |> Floki . raw_html ( ) , toc }
144
150
end
145
151
146
- defp get_level_for_toc ( [ ] , _ ) , do: 1
147
- defp get_level_for_toc ( _ , level ) , do: level |> String . to_integer ( )
152
+ defp get_toc_level ( [ ] , header , _ ) , do:
153
+ { :level , 1 , :positions , % { level: 1 , header: header , index: 0 } }
154
+
155
+ defp get_toc_level ( _ , header , % { level: curr_level , header: curr_header , index: idx } )
156
+ when header == curr_header , do:
157
+ { :level , curr_level , :positions , % { level: curr_level , header: curr_header , index: idx + 1 } }
158
+
159
+ defp get_toc_level ( toc , header , % { level: curr_level , header: curr_header , index: idx } )
160
+ when header < curr_header do
161
+ [ _ | reversed_toc ] = toc |> Enum . reverse ( )
162
+
163
+ { _ , level } =
164
+ reversed_toc
165
+ |> Enum . reduce ( { curr_header , curr_level } , fn
166
+ _ , { acc_header , _ } = acc
167
+ when acc_header <= header ->
168
+ acc
169
+
170
+ % { header: i_header , level: i_level } , _acc
171
+ when i_header < header ->
172
+ { i_header , i_level + 1 }
173
+
174
+ % { header: i_header , level: i_level } , _acc
175
+ when i_header == header ->
176
+ { i_header , i_level }
177
+
178
+ % { header: i_header } , acc
179
+ when i_header > header ->
180
+ acc
181
+ end )
182
+
183
+ { :level , level , :positions , % { level: level , header: header , index: idx + 1 } }
184
+ end
185
+
186
+ defp get_toc_level ( _ , header , % { level: curr_level , header: curr_header , index: idx } )
187
+ when header > curr_header do
188
+ level = curr_level + 1
189
+ { :level , level , :positions , % { level: level , header: header , index: idx + 1 } }
190
+ end
191
+
192
+ defp parse_header_level ( level ) , do: String . to_integer ( level )
148
193
149
194
def strip_in_between_space ( html ) ,
150
195
do:
0 commit comments