Skip to content

Commit a8eff76

Browse files
committed
feat: Add some modifications to add direct link to filters
1 parent 87c7b7f commit a8eff76

File tree

3 files changed

+138
-8
lines changed

3 files changed

+138
-8
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
{"learnocaml_version":"1","kind":"exercise","stars":0,
1+
{"learnocaml_version":"1","kind":"exercise","stars":1,
22
"title":"Demo of the exercise environment (MD version)"}

src/app/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
(libraries ezjsonm
3636
ace
3737
sha
38+
re.pcre
3839
learnocaml_repository
3940
learnocaml_app_common
4041
learnocaml_toplevel

src/app/learnocaml_index_main.ml

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ open Js_of_ocaml
1010
open Js_of_ocaml_tyxml
1111
open Js_of_ocaml_lwt
1212
open Js_utils
13+
open Re.Pcre
1314
open Lwt
1415
open Learnocaml_data
1516
open Learnocaml_common
1617
open Learnocaml_config
1718

19+
1820
module H = Tyxml_js.Html5
1921

2022
module El = struct
@@ -85,8 +87,76 @@ let (exercise_filter_signal: string option React.signal), set_exercise_filter =
8587
let (exercise_sort_signal: exercise_ordering React.signal), set_exercise_sort =
8688
React.S.create By_category
8789

90+
let (expand_state: string list React.signal), set_expand_state =
91+
React.S.create []
92+
93+
let encode str =
94+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp ",") ~subst:(fun _ -> "-c") (
95+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "&") ~subst:(fun _ -> "-a") (
96+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "=") ~subst:(fun _ -> "-e") (
97+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-") ~subst:(fun _ -> "--") str)))
98+
let decode str =
99+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "--") ~subst:(fun _ -> "-") (
100+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-e") ~subst:(fun _ -> "=") (
101+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-a") ~subst:(fun _ -> "&") (
102+
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-c") ~subst:(fun _ -> ",") str)))
103+
104+
let rec update_expand ?value fragment =
105+
match value with
106+
| Some v ->
107+
if (List.mem_assoc "expand" fragment) then
108+
match fragment with
109+
| [] ->
110+
update_expand ~value:v []
111+
| ("expand", x)::t ->
112+
let expand_list = Re.Pcre.split ~rex:(Re.Pcre.regexp ",") x in
113+
let new_expand_list =
114+
if (List.mem v expand_list) then
115+
begin
116+
let filtered_list = List.filter (fun x -> x <> v) expand_list in
117+
if (filtered_list = []) then [""] else filtered_list
118+
end
119+
else
120+
begin
121+
if (expand_list = [""]) then [v] else v::expand_list
122+
end
123+
in
124+
let join l =
125+
match l with
126+
| [] -> ""
127+
| h::t -> List.fold_left (fun acc x -> acc ^ "," ^ x) h t
128+
in
129+
let joined_expand = join new_expand_list in
130+
set_expand_state new_expand_list;
131+
(*if (joined_expand <> "") then*) ("expand", joined_expand)::t (*else t*)
132+
| h::t ->
133+
h::(update_expand ~value:v t)
134+
else
135+
begin
136+
set_expand_state [v];
137+
fragment@[("expand",v)]
138+
end
139+
| None ->
140+
set_expand_state [];
141+
List.filter (fun (k, _) -> k <> "expand") fragment
142+
143+
let update_sort value fragment =
144+
let filtered_fragment = List.remove_assoc "sort" (update_expand fragment) in
145+
filtered_fragment@[("sort",value)]
146+
147+
let update_fragment key value =
148+
let fragment = Js_utils.parse_fragment () in
149+
let filtered_fragment =
150+
if (key = "expand") then
151+
let v = (Uri.pct_encode (encode value)) in
152+
update_expand ~value:v fragment
153+
else
154+
update_sort value fragment
155+
in
156+
Js_utils.set_fragment (filtered_fragment)
157+
88158
let make_exercises_to_display_signal index =
89-
let get_index exo_sort exo_filter =
159+
let get_index exo_sort exo_filter _expand =
90160
let index =
91161
match exo_sort with
92162
| By_category -> index
@@ -113,7 +183,7 @@ let make_exercises_to_display_signal index =
113183
StrMap.fold (fun skill exercises acc ->
114184
(skill,
115185
{Exercise.Index.title = skill;
116-
contents = Exercise.Index.Exercises (List.rev exercises)})
186+
contents = Exercise.Index.Exercises (List.rev exercises)})
117187
:: acc)
118188
by_skill []
119189
in
@@ -165,14 +235,31 @@ let make_exercises_to_display_signal index =
165235
Exercise.Index.contents = Exercise.Index.Exercises []; }]
166236
else index
167237
in
168-
React.S.l2 get_index exercise_sort_signal exercise_filter_signal
238+
React.S.l3 get_index exercise_sort_signal exercise_filter_signal expand_state
169239

170240
let retain_signals = ref (React.S.const ())
171241
(* Used to register signals as GC roots *)
172242

173243
let exercises_tab token : tab_handler =
174244
fun _ _ () ->
175245
let open Tyxml_js.Html5 in
246+
let () =
247+
Dom_html.window##.onhashchange := Dom_html.handler (fun _ ->
248+
let fragment = Js_utils.parse_fragment () in
249+
(match List.assoc_opt "sort" fragment with
250+
| Some "category" -> set_exercise_sort By_category
251+
| Some "skill" -> set_exercise_sort By_skill
252+
| Some "difficulty" -> set_exercise_sort By_difficulty
253+
| _ -> ());
254+
let expands = List.assoc_opt "expand" fragment in
255+
let ids expands =
256+
match expands with
257+
| None -> []
258+
| Some e -> Re.Pcre.split ~rex:(Re.Pcre.regexp ",") e
259+
in
260+
set_expand_state (ids expands);
261+
Js._true)
262+
in
176263
show_loading [%i"Loading exercises"] @@ fun () ->
177264
Lwt_js.sleep 0.5 >>= fun () ->
178265
retrieve (Learnocaml_api.Exercise_index token)
@@ -236,6 +323,12 @@ let exercises_tab token : tab_handler =
236323
]
237324
] ]
238325
in
326+
let update_expand_class id ids =
327+
if (List.mem id ids) then
328+
[]
329+
else
330+
["collapse"]
331+
in
239332
let rec format_exercise_list index =
240333
match index with
241334
| Exercise.Index.Exercises el ->
@@ -248,7 +341,24 @@ let exercises_tab token : tab_handler =
248341
List.map (fun (id, grp) ->
249342
let clas =
250343
"group-title" ::
251-
match gl with [] | [_] -> [] | _ -> ["collapsed"]
344+
match gl with
345+
| [] -> []
346+
| [_] ->
347+
let expand_ids = React.S.value expand_state in
348+
if (expand_ids = []) then
349+
begin
350+
set_expand_state [id];
351+
update_fragment "expand" id;
352+
[]
353+
end
354+
else
355+
update_expand_class id expand_ids
356+
| _ ->
357+
let expand_ids = React.S.value expand_state in
358+
if (expand_ids = []) then
359+
["collapsed"]
360+
else
361+
update_expand_class id expand_ids
252362
in
253363
let title =
254364
H.div ~a:[a_id id; a_class clas]
@@ -257,8 +367,9 @@ let exercises_tab token : tab_handler =
257367
let exos = format_exercise_list grp.Exercise.Index.contents in
258368
Manip.Ev.onclick title
259369
(fun _ ->
260-
ignore (Manip.toggleClass title "collapsed");
261-
false);
370+
update_fragment "expand" id;
371+
ignore (Manip.toggleClass title "collapsed");
372+
false);
262373
H.li [title; exos])
263374
gl
264375
in
@@ -269,7 +380,14 @@ let exercises_tab token : tab_handler =
269380
List.map (fun (id, sort, name) ->
270381
let btn = button ~a:[a_id id] [ txt name ] in
271382
Manip.Ev.onclick btn
272-
(fun _ -> set_exercise_sort sort; true);
383+
(fun _ ->
384+
let sort_value =
385+
match sort with
386+
| By_category -> "category"
387+
| By_skill -> "skill"
388+
| By_difficulty -> "difficulty"
389+
in
390+
update_fragment "sort" sort_value;set_exercise_sort sort;true);
273391
let signal =
274392
React.S.map (fun s ->
275393
(if sort = s then Manip.addClass else Manip.removeClass)
@@ -311,6 +429,17 @@ let exercises_tab token : tab_handler =
311429
in
312430
retain_signals :=
313431
React.S.merge (fun () () -> ()) () (list_update_signal :: btns_sigs);
432+
let () =
433+
ignore (React.S.map (fun expanded_ids ->
434+
List.iter (fun id ->
435+
match Dom_html.getElementById_opt id with
436+
| Some elt ->
437+
let class_list = elt##.classList in
438+
if Js.to_bool (class_list##contains (Js.string "group-title")) &&
439+
Js.to_bool (class_list##contains (Js.string "collapsed"))
440+
then ignore (class_list##remove (Js.string "collapsed"))
441+
| None -> ()) expanded_ids) expand_state)
442+
in
314443
Lwt.return pane_div
315444

316445
let playground_tab token : tab_handler =

0 commit comments

Comments
 (0)