@@ -28,13 +28,36 @@ impl HelperDef for RenderToc {
2828 serde_json:: value:: from_value :: < Vec < BTreeMap < String , String > > > ( c. as_json ( ) . clone ( ) )
2929 . map_err ( |_| RenderError :: new ( "Could not decode the JSON data" ) )
3030 } ) ?;
31- let current = rc
31+ let current_path = rc
3232 . evaluate ( ctx, "@root/path" ) ?
3333 . as_json ( )
3434 . as_str ( )
35- . ok_or_else ( || RenderError :: new ( "Type error for `path`, string expected" ) ) ?
35+ . ok_or ( RenderError :: new ( "Type error for `path`, string expected" ) ) ?
3636 . replace ( "\" " , "" ) ;
3737
38+ let current_section = rc
39+ . evaluate ( ctx, "@root/section" ) ?
40+ . as_json ( )
41+ . as_str ( )
42+ . map ( str:: to_owned)
43+ . unwrap_or_default ( ) ;
44+
45+ let fold_enable = rc
46+ . evaluate ( ctx, "@root/fold_enable" ) ?
47+ . as_json ( )
48+ . as_bool ( )
49+ . ok_or ( RenderError :: new (
50+ "Type error for `fold_enable`, bool expected" ,
51+ ) ) ?;
52+
53+ let fold_level = rc
54+ . evaluate ( ctx, "@root/fold_level" ) ?
55+ . as_json ( )
56+ . as_u64 ( )
57+ . ok_or ( RenderError :: new (
58+ "Type error for `fold_level`, u64 expected" ,
59+ ) ) ?;
60+
3861 out. write ( "<ol class=\" chapter\" >" ) ?;
3962
4063 let mut current_level = 1 ;
@@ -46,10 +69,23 @@ impl HelperDef for RenderToc {
4669 continue ;
4770 }
4871
49- let level = if let Some ( s) = item. get ( "section" ) {
50- s . matches ( '.' ) . count ( )
72+ let ( section , level) = if let Some ( s) = item. get ( "section" ) {
73+ ( s . as_str ( ) , s . matches ( '.' ) . count ( ) )
5174 } else {
52- 1
75+ ( "" , 1 )
76+ } ;
77+
78+ let is_expanded = {
79+ if !fold_enable {
80+ // Disable fold. Expand all chapters.
81+ true
82+ } else if !section. is_empty ( ) && current_section. starts_with ( section) {
83+ // The section is ancestor or the current section itself.
84+ true
85+ } else {
86+ // Levels that are larger than this would be folded.
87+ level - 1 < fold_level as usize
88+ }
5389 } ;
5490
5591 if level > current_level {
@@ -58,20 +94,16 @@ impl HelperDef for RenderToc {
5894 out. write ( "<ol class=\" section\" >" ) ?;
5995 current_level += 1 ;
6096 }
61- out . write ( "<li>" ) ?;
97+ write_li_open_tag ( out , is_expanded , false ) ?;
6298 } else if level < current_level {
6399 while level < current_level {
64100 out. write ( "</ol>" ) ?;
65101 out. write ( "</li>" ) ?;
66102 current_level -= 1 ;
67103 }
68- out . write ( "<li>" ) ?;
104+ write_li_open_tag ( out , is_expanded , false ) ?;
69105 } else {
70- out. write ( "<li" ) ?;
71- if item. get ( "section" ) . is_none ( ) {
72- out. write ( " class=\" affix\" " ) ?;
73- }
74- out. write ( ">" ) ?;
106+ write_li_open_tag ( out, is_expanded, item. get ( "section" ) . is_none ( ) ) ?;
75107 }
76108
77109 // Link
@@ -87,11 +119,11 @@ impl HelperDef for RenderToc {
87119 . replace ( "\\ " , "/" ) ;
88120
89121 // Add link
90- out. write ( & utils:: fs:: path_to_root ( & current ) ) ?;
122+ out. write ( & utils:: fs:: path_to_root ( & current_path ) ) ?;
91123 out. write ( & tmp) ?;
92124 out. write ( "\" " ) ?;
93125
94- if path == & current {
126+ if path == & current_path {
95127 out. write ( " class=\" active\" " ) ?;
96128 }
97129
@@ -134,6 +166,13 @@ impl HelperDef for RenderToc {
134166 out. write ( "</a>" ) ?;
135167 }
136168
169+ // Render expand/collapse toggle
170+ if let Some ( flag) = item. get ( "has_sub_items" ) {
171+ let has_sub_items = flag. parse :: < bool > ( ) . unwrap_or_default ( ) ;
172+ if fold_enable && has_sub_items {
173+ out. write ( "<a class=\" toggle\" ><div>❱</div></a>" ) ?;
174+ }
175+ }
137176 out. write ( "</li>" ) ?;
138177 }
139178 while current_level > 1 {
@@ -146,3 +185,19 @@ impl HelperDef for RenderToc {
146185 Ok ( ( ) )
147186 }
148187}
188+
189+ fn write_li_open_tag (
190+ out : & mut dyn Output ,
191+ is_expanded : bool ,
192+ is_affix : bool ,
193+ ) -> Result < ( ) , std:: io:: Error > {
194+ let mut li = String :: from ( "<li class=\" " ) ;
195+ if is_expanded {
196+ li. push_str ( "expanded " ) ;
197+ }
198+ if is_affix {
199+ li. push_str ( "affix " ) ;
200+ }
201+ li. push_str ( "\" >" ) ;
202+ out. write ( & li)
203+ }
0 commit comments