Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve description entrypoint #423

Merged
merged 2 commits into from Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 57 additions & 11 deletions src/app/learnocaml_description_main.ml
Expand Up @@ -8,13 +8,47 @@ open Learnocaml_data.Exercise.Meta
let init_tabs, select_tab =
mk_tab_handlers "text" ["text"; "meta"]

type encoded_token =
{
arg_name: string;
raw_arg: string;
token: Learnocaml_data.Token.t
}

(** [get_arg_token ()] read (and decode if need be) the user token.

@return [Some encoded_token] if a token was successfully read.
It returns [None] if no token was specified in the URL.
An exception is raised if an incorrect token was specified. *)
let get_encoded_token () =
match arg "token" with (* arg in plain text, deprecated in learn-ocaml 0.13 *)
| raw_arg ->
let token = Learnocaml_data.Token.parse raw_arg in
Some { arg_name = "token"; raw_arg; token }
| exception Not_found ->
match arg "token1" with (* encoding algo 1: space-padded token |> base64 *)
| raw_arg ->
begin match Base64.decode ~pad:true raw_arg with
(* ~pad:false would work also, but ~pad:true is stricter *)
| Ok pad_token ->
Some { arg_name = "token1"; raw_arg;
token = Learnocaml_data.Token.parse (String.trim pad_token) }
| Error (`Msg msg) -> failwith msg
end
| exception Not_found -> None

module Exercise_link =
struct
let exercise_link ?(cl = []) id content =
let token = Learnocaml_data.Token.(to_string (parse (arg "token"))) in
Tyxml_js.Html5.(a ~a:[ a_href ("/description/"^id^"#token="^token);
a_class cl ]
content)
match get_encoded_token () with
| Some { arg_name; raw_arg; _ } ->
Tyxml_js.Html5.(a ~a:[ a_href
(Printf.sprintf "/description/%s#%s=%s"
id arg_name raw_arg);
a_class cl ]
content)
| None ->
Tyxml_js.Html5.(a ~a:[ a_href "#" ; a_class cl ] content)
end

module Display = Display_exercise(Exercise_link)
Expand All @@ -29,8 +63,8 @@ let () =
Learnocaml_local_storage.init () ;
let title_container = find_component "learnocaml-exo-tab-text-title" in
let text_container = find_component "learnocaml-exo-tab-text-descr" in
try begin
let token = Learnocaml_data.Token.parse (arg "token") in
match get_encoded_token () with
| Some { arg_name = _; raw_arg = _; token } -> begin
let exercise_fetch =
retrieve (Learnocaml_api.Exercise (Some token, id))
in
Expand All @@ -51,9 +85,21 @@ let () =
d##write (Js.string (exercise_text ex_meta exo));
d##close) ;
(* display meta *)
display_meta (Some token) ex_meta id
display_meta (Some token) ex_meta id >>= fun () ->
(* hide the initial/loading phase curtain *)
Lwt.return @@ hide_loading ~id:"learnocaml-exo-loading" ()
end
with Not_found ->
Lwt.return @@
Manip.replaceChildren text_container
Tyxml_js.Html5.[ h1 [ txt "Error: Missing token" ] ]
| None ->
let elt = find_div_or_append_to_body "learnocaml-exo-loading" in
Manip.(addClass elt "loading-layer") ;
Manip.(removeClass elt "loaded") ;
Manip.(addClass elt "loading") ;
Manip.replaceChildren elt
Tyxml_js.Html5.[
h1 [ txt "Error: missing token. \
Use a link from ";
(* Note: could be put in a global constant *)
a ~a:[ a_href "https://github.com/pfitaxel/learn-ocaml.el" ]
[ txt "learn-ocaml-mode" ];
txt "?" ] ];
Lwt.return_unit
10 changes: 10 additions & 0 deletions static/css/learnocaml_description.css
Expand Up @@ -141,6 +141,16 @@ body {

/* BEGIN excerpt from learnocaml_exercise.css */

/* -------------------- loading splash screen --------------------- */
#learnocaml-exo-loading {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
}
#learnocaml-exo-loading.loading,
#learnocaml-exo-loading.loaded {
background: rgba(200,200,200,0.9);
}

.learnocaml-exo-meta-category ~ .exercise + .exercise {
border-top: 1px #333 solid;
}
Expand Down
21 changes: 21 additions & 0 deletions static/description.html
Expand Up @@ -19,6 +19,27 @@
</head>

<body>
<!-- Should be kept untouched. -->
<div style="display:none">
<!-- (Weakly) preload images. -->
<img src="/icons/tryocaml_loading_1.gif"><img src="/icons/tryocaml_loading_2.gif">
<img src="/icons/tryocaml_loading_3.gif"><img src="/icons/tryocaml_loading_4.gif">
<img src="/icons/tryocaml_loading_5.gif"><img src="/icons/tryocaml_loading_6.gif">
<img src="/icons/tryocaml_loading_7.gif"><img src="/icons/tryocaml_loading_8.gif">
<img src="/icons/tryocaml_loading_9.gif">
</div>
<!-- Three states: .initial, .loading and .loaded.
Set to .loaded when initial loading finished.
Set to .loading while loading, then to .loaded. -->
<div id="learnocaml-exo-loading" class="loading-layer initial">
<div id="chamo"><img id="chamo-img" src="/icons/tryocaml_loading_5.gif"></div>
<div class="messages"><ul><li id="txt_preparing">Preparing the environment</li></ul></div>
</div>
<script language="JavaScript">
var n = Math.floor (Math.random () * 8.99) + 1;
document.getElementById('chamo-img').src = learnocaml_config.baseUrl + '/icons/tryocaml_loading_' + n + '.gif';
</script>
<!-- Anything below could be recreated dynamically, but IDs must be kept. -->
<div id="learnocaml-exo-toolbar">
<div class="logo">
<img src="/icons/logo_ocaml.svg">
Expand Down