Skip to content

Commit 0b150b9

Browse files
authored
Merge pull request #549 from AltGr/teacher-page-improvements
Various improvements to the teacher page, incl. some inline documentation
2 parents 41c9b65 + e060517 commit 0b150b9

14 files changed

+702
-186
lines changed

Makefile

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,22 @@ static/dune:
3535
# Generates up-to-date translation template for lang % from the sources
3636
LANGS = $(patsubst translations/%.po,%,$(wildcard translations/*.po))
3737
translations/$(LANGS:=.pot):
38-
@for f in $(LANGS); do echo >> translations/$$f.po; done
39-
@rm -f translations/*.pot
38+
@for f in $(LANGS); do \
39+
echo >> translations/$$f.po; \
40+
rm -f translations/$$f.pot; \
41+
cp translations/$$f.po.header translations/$$f.pot; \
42+
done
4043
@${DUNE} clean ${DUNE_ARGS}
4144
-rm -f ${INDEX_ODOC_PATH}
4245
@DUMP_POT=1 ${DUNE} build ${DUNE_ARGS} -j 1
4346
@for f in $(LANGS); do \
4447
mv translations/$$f.pot translations/$$f.pot.bak; \
45-
msguniq translations/$$f.pot.bak > translations/$$f.pot; \
46-
rm translations/$$f.pot.bak; \
48+
msguniq -t utf-8 translations/$$f.pot.bak > translations/$$f.pot \
49+
&& rm translations/$$f.pot.bak; \
4750
done
4851

52+
.PHONY: translations/$(LANGS:=.pot)
53+
4954
# Updates existing translations (.po) for the latest source template
5055
update-%-translation: translations/%.pot
5156
@msgmerge -U translations/$*.po translations/$*.pot

src/app/dune

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
learnocaml_toplevel
4040
js_of_ocaml-ppx
4141
ocplib_i18n)
42-
(modules Learnocaml_teacher_tab
42+
(modules Learnocaml_teacher_tab_doc
43+
Learnocaml_teacher_tab
4344
Learnocaml_index_main)
4445
(preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx))
4546
)

src/app/learnocaml_common.ml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,25 @@ let confirm ~title ?(ok_label=[%i"OK"]) ?(cancel_label=[%i"Cancel"]) contents f
143143
close_button cancel_label;
144144
]
145145

146-
let ask_string ~title ?(ok_label=[%i"OK"]) contents =
146+
let ask_string ~title ?(ok_label=[%i"OK"]) ?(may_cancel=true) contents =
147147
let input_field =
148148
H.input ~a:[
149149
H.a_input_type `Text;
150150
] ()
151151
in
152152
let result_t, up = Lwt.wait () in
153-
ext_alert ~title (contents @ [input_field]) ~buttons:[
154-
box_button ok_label (fun () -> Lwt.wakeup up @@ Manip.value input_field)
155-
];
153+
let validate _ =
154+
Lwt.wakeup up @@ Manip.value input_field
155+
in
156+
Manip.Ev.onreturn input_field validate;
157+
let buttons =
158+
box_button ok_label validate
159+
:: (if may_cancel
160+
then [close_button [%i"Cancel"]]
161+
else [])
162+
in
163+
ext_alert ~title (contents @ [input_field]) ~buttons;
164+
Manip.focus input_field;
156165
result_t
157166

158167
let default_exn_printer = function
@@ -1157,7 +1166,7 @@ let get_token ?(has_server = true) () =
11571166
Lwt.return
11581167
with
11591168
Not_found ->
1160-
ask_string ~title:"Token"
1169+
ask_string ~title:"Token" ~may_cancel:false
11611170
[H.txt [%i"Enter your token"]]
11621171
>>= fun input_tok ->
11631172
let token = Token.parse (input_tok) in

src/app/learnocaml_common.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ val confirm :
4545
val ask_string :
4646
title: string ->
4747
?ok_label: string ->
48+
?may_cancel: bool ->
4849
[< Html_types.div_content > `Input] Tyxml_js.Html.elt list ->
4950
string Lwt.t
5051

src/app/learnocaml_teacher_tab.ml

Lines changed: 102 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,46 @@ let tag_addremove list_id placeholder add_fun remove_fun =
6868
] [ H.txt "\xe2\x9e\x96" (* U+2796 heavy minus sign *) ];
6969
]
7070

71+
let help_button name (title,md_text) =
72+
let dialog () =
73+
let text_div =
74+
let d =
75+
H.div []
76+
~a:[H.a_class ["doc-popup-body"]]
77+
in
78+
(* Manip.SetCss.maxHeight d "85vh";
79+
* Manip.SetCss.overflowY d "auto"; *)
80+
let doc_html_string =
81+
Omd.(md_text |> of_string |> to_html)
82+
in
83+
Manip.setInnerHtml d doc_html_string;
84+
d
85+
in
86+
Learnocaml_common.ext_alert ~title [text_div]
87+
in
88+
H.button ~a:[
89+
H.a_id ("button_help_"^name);
90+
H.a_onclick (fun _ -> dialog (); true);
91+
H.a_style "margin-left: 1em;";
92+
] [H.txt "?"]
93+
7194
let rec teacher_tab token _select _params () =
7295
let action_new_token () =
73-
retrieve (Learnocaml_api.Create_teacher_token token)
96+
Learnocaml_common.ask_string
97+
~title:"NEW TEACHER TOKEN"
98+
[H.txt @@ "Enter a nickname for the new token:"]
99+
>>= fun nickname ->
100+
let nick = match String.trim nickname with
101+
| "" -> None
102+
| s -> Some s
103+
in
104+
retrieve (Learnocaml_api.Create_teacher_token (token, nick))
74105
>|= fun new_token ->
75106
alert ~title:[%i"TEACHER TOKEN"]
76107
(Printf.sprintf [%if"New teacher token created:\n%s\n\n\
77108
write it down."]
78109
(Token.to_string new_token))
79110
in
80-
let action_csv_export () =
81-
retrieve (Learnocaml_api.Students_csv (token, [], []))
82-
>|= fun csv ->
83-
Learnocaml_common.fake_download
84-
~name:"learnocaml.csv"
85-
~contents:(Js.string csv)
86-
in
87111
let indent_style lvl =
88112
H.a_style (Printf.sprintf "text-align: left; padding-left: %dem;" lvl)
89113
in
@@ -183,6 +207,23 @@ let rec teacher_tab token _select _params () =
183207
let assignment_change = ref (fun _ -> assert false) in
184208
let assignment_remove = ref (fun _ -> assert false) in
185209

210+
let action_csv_export () =
211+
let exercises =
212+
Hashtbl.to_seq_keys selected_exercises |>
213+
List.of_seq
214+
in
215+
let students =
216+
Hashtbl.to_seq_keys selected_students |>
217+
Seq.filter_map (function `Token tk -> Some tk | `Any -> None) |>
218+
List.of_seq
219+
in
220+
retrieve (Learnocaml_api.Students_csv (token, exercises, students))
221+
>|= fun csv ->
222+
Learnocaml_common.fake_download
223+
~name:"learnocaml.csv"
224+
~contents:(Js.string csv)
225+
in
226+
186227
(* Exercises table *)
187228
let rec mk_table group_level acc status group =
188229
match group with
@@ -211,7 +252,7 @@ let rec teacher_tab token _select _params () =
211252
in
212253
let open_partition_ () =
213254
Lwt.async (fun () ->
214-
ask_string ~title:"Choose a function name"
255+
ask_string ~title:"Partitioning of student solutions"
215256
[H.txt @@ "Choose a function name to partition codes from "^ id ^": "]
216257
>|= fun funname ->
217258
let _win =
@@ -258,12 +299,13 @@ let rec teacher_tab token _select _params () =
258299
H.td [stars_div meta.Exercise.Meta.stars];
259300
H.td [
260301
let cls, text =
261-
if Token.Map.is_empty ES.(st.assignments.token_map) then
262-
match ES.(st.assignments.default) with
263-
| ES.Open -> "exo_open", [%i"Open"]
264-
| ES.Closed -> "exo_closed", [%i"Closed"]
265-
| ES.Assigned _ -> "exo_assigned", [%i"Assigned"]
266-
else "exo_assigned", [%i"Assigned"]
302+
match Token.Map.is_empty ES.(st.assignments.token_map),
303+
ES.(st.assignments.default) with
304+
| true, ES.Open -> "exo_open", [%i"Open"]
305+
| true, ES.Closed -> "exo_closed", [%i"Closed"]
306+
| _, (ES.Assigned _ | ES.Closed) ->
307+
"exo_assigned", [%i"Assigned"]
308+
| false, ES.Open -> "exo_assigned", [%i"Open/Assg"]
267309
in
268310
H.span ~a:[H.a_class [cls]] [H.txt text]
269311
];
@@ -328,11 +370,14 @@ let rec teacher_tab token _select _params () =
328370
let exercise_skills_list_id = "exercise_skills_list" in
329371
let exercises_div =
330372
let legend =
331-
H.legend ~a:[
332-
H.a_onclick (fun _ ->
333-
!toggle_selected_exercises (all_exercises !exercises_index);
334-
true);
335-
] [H.txt [%i"Exercises"]; H.txt " \xe2\x98\x90" (* U+2610 *)]
373+
H.legend [
374+
H.span
375+
[ H.txt [%i"Exercises"]; H.txt " \xe2\x98\x90" (* U+2610 *) ]
376+
~a:[H.a_onclick (fun _ ->
377+
!toggle_selected_exercises (all_exercises !exercises_index);
378+
true)];
379+
help_button "exercises" Learnocaml_teacher_tab_doc.exercises_pane_md
380+
]
336381
in
337382
H.div ~a:[H.a_id "exercises_pane"; H.a_class ["learnocaml_pane"]] [
338383
H.div ~a:[H.a_id "exercises_filter_box"] [
@@ -530,23 +575,26 @@ let rec teacher_tab token _select _params () =
530575
in
531576
let students_div =
532577
let legend =
533-
H.legend ~a:[
534-
H.a_onclick (fun _ ->
535-
let all =
536-
Token.Map.fold (fun k _ acc -> (`Token k)::acc)
537-
!students_map [`Any]
538-
in
539-
let all =
540-
List.filter (fun t ->
541-
not (Manip.hasClass (find_component (student_line_id t))
542-
"student_hidden"))
543-
all
544-
in
545-
!toggle_selected_students all;
546-
true
547-
);
548-
] [H.txt [%i"Students"];
549-
H.txt " \xe2\x98\x90" (* U+2610 ballot box *)]
578+
H.legend [
579+
H.span
580+
[ H.txt [%i"Students"];
581+
H.txt " \xe2\x98\x90" (* U+2610 ballot box *) ]
582+
~a:[H.a_onclick (fun _ ->
583+
let all =
584+
Token.Map.fold (fun k _ acc -> (`Token k)::acc)
585+
!students_map [`Any]
586+
in
587+
let all =
588+
List.filter (fun t ->
589+
not (Manip.hasClass (find_component (student_line_id t))
590+
"student_hidden"))
591+
all
592+
in
593+
!toggle_selected_students all;
594+
true
595+
)];
596+
help_button "students" Learnocaml_teacher_tab_doc.students_pane_md
597+
]
550598
in
551599
H.div ~a:[H.a_id "students_pane"; H.a_class ["learnocaml_pane"]] [
552600
H.div ~a:[H.a_id "students_filter_box"] [
@@ -812,12 +860,10 @@ let rec teacher_tab token _select _params () =
812860
ES.(default_assignment st.assignments = Open))
813861
ids
814862
then ES.(fun assg ->
815-
(* fixme: invisible change if the exercise is assigned! *)
816863
match default_assignment assg with
817864
| Open -> set_default_assignment assg Closed
818865
| _ -> assg)
819866
else ES.(fun assg ->
820-
(* fixme: invisible change if the exercise is assigned! *)
821867
match default_assignment assg with
822868
| Closed -> set_default_assignment assg Open
823869
| _ -> assg)
@@ -841,9 +887,16 @@ let rec teacher_tab token _select _params () =
841887
Manip.appendChild exercises_div exercise_control_div;
842888
let assignments_div = H.div [] in
843889
let control_div =
890+
let legend =
891+
H.legend [
892+
H.txt [%i"Assignments"];
893+
help_button "assignments"
894+
Learnocaml_teacher_tab_doc.assignments_pane_md
895+
]
896+
in
844897
H.div ~a:[H.a_id "control_pane"] [
845898
H.fieldset
846-
~legend:(H.legend [H.txt [%i"Assignments"]])
899+
~legend
847900
[assignments_div];
848901
]
849902
in
@@ -932,7 +985,7 @@ let rec teacher_tab token _select _params () =
932985
H.li ~a: [ H.a_onclick (fun _ -> Lwt.async action_new_token; true) ]
933986
[ H.txt [%i"Create new teacher token"] ];
934987
H.li ~a: [ H.a_onclick (fun _ -> Lwt.async action_csv_export; true) ]
935-
[ H.txt [%i"Download student data as CSV"] ];
988+
[ H.txt [%i"Download the data for selected students/exercises as CSV"] ];
936989
]
937990
];
938991
]
@@ -1102,10 +1155,16 @@ let rec teacher_tab token _select _params () =
11021155
if SMap.is_empty !status_changes &&
11031156
Token.Map.is_empty !students_changes then
11041157
(Manip.replaceChildren status_text_div [];
1105-
Manip.removeClass status_text_div "warning")
1158+
Manip.removeClass status_text_div "warning";
1159+
Option.iter
1160+
(fun b -> Manip.removeClass b "warning")
1161+
(Manip.by_id "button_apply"))
11061162
else
11071163
(Manip.replaceChildren status_text_div [H.txt [%i"Unsaved changes"]];
1108-
Manip.addClass status_text_div "warning")
1164+
Manip.addClass status_text_div "warning";
1165+
Option.iter
1166+
(fun b -> Manip.addClass b "warning")
1167+
(Manip.by_id "button_apply"))
11091168
end;
11101169
toggle_selected_exercises := begin
11111170
fun ?force ?(update = force=None) ids ->

0 commit comments

Comments
 (0)