diff --git a/src/app/learnocaml_common.ml b/src/app/learnocaml_common.ml index b6bf69532..cc8b4fcca 100644 --- a/src/app/learnocaml_common.ml +++ b/src/app/learnocaml_common.ml @@ -948,6 +948,42 @@ let set_nickname_div () = | nickname -> Manip.setInnerText nickname_div nickname | exception Not_found -> () +(* setup for the prelude in the description page (in description_main.ml) *) +let setup_tab_text_prelude_pane prelude = + if prelude = "" then () else + let iframe_pane = find_component "learnocaml-exo-tab-text-descr" in + let prelude_pane = find_component "learnocaml-exo-tab-text-prelude" in + let open Tyxml_js.Html5 in + let state = + ref (match arg "tab_text_prelude" with + | exception Not_found -> true + | "shown" -> true + | "hidden" -> false + | _ -> failwith "Bad format for argument prelude.") in + let prelude_btn = button [] in + let prelude_title = h1 [ txt [%i"OCaml prelude"] ; + prelude_btn ] in + let prelude_container = + pre ~a: [ a_class [ "toplevel-code" ] ] + (Learnocaml_toplevel_output.format_ocaml_code prelude) in + let update () = + if !state then begin + Manip.replaceChildren prelude_btn [ txt ("↳ "^[%i"Hide"]) ] ; + Manip.SetCss.display prelude_container "" ; + Manip.SetCss.top iframe_pane "241px"; + set_arg "tab_text_prelude" "shown" + end else begin + Manip.replaceChildren prelude_btn [ txt ("↰ "^[%i"Show"]) ] ; + Manip.SetCss.display prelude_container "none" ; + Manip.SetCss.top iframe_pane "90px"; + set_arg "tab_text_prelude" "hidden" + end in + update () ; + Manip.Ev.onclick prelude_btn + (fun _ -> state := not !state ; update () ; true) ; + Manip.appendChildren prelude_pane + [ prelude_title ; prelude_container ] + let setup_prelude_pane ace prelude = if prelude = "" then () else let editor_pane = find_component "learnocaml-exo-editor-pane" in diff --git a/src/app/learnocaml_common.mli b/src/app/learnocaml_common.mli index d4f82f464..5ace9a36f 100644 --- a/src/app/learnocaml_common.mli +++ b/src/app/learnocaml_common.mli @@ -222,6 +222,8 @@ val typecheck : val set_nickname_div : unit -> unit +val setup_tab_text_prelude_pane : string -> unit + val setup_prelude_pane : 'a Ace.editor -> string -> unit val get_token : ?has_server:bool -> unit -> Learnocaml_data.student Learnocaml_data.token option Lwt.t diff --git a/src/app/learnocaml_description_main.ml b/src/app/learnocaml_description_main.ml index 29f53b850..44ac7be9c 100644 --- a/src/app/learnocaml_description_main.ml +++ b/src/app/learnocaml_description_main.ml @@ -16,10 +16,10 @@ module Exercise_link = a_class cl ] content) end - -module Display = Display_exercise(Exercise_link) + +module Display = Display_exercise(Exercise_link) open Display - + let () = run_async_with_log @@ fun () -> let id = match Url.Current.path with @@ -27,7 +27,8 @@ let () = String.concat "/" (List.map Url.urldecode (List.filter ((<>) "") p)) | _ -> arg "id" in Learnocaml_local_storage.init () ; - let text_container = find_component "learnocaml-exo-tab-text" in + 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 let exercise_fetch = @@ -35,11 +36,13 @@ let () = in init_tabs (); exercise_fetch >>= fun (ex_meta, exo, _deadline) -> - (* display exercise questions *) + (* display exercise questions and prelude *) + setup_tab_text_prelude_pane Learnocaml_exercise.(decipher File.prelude exo); let text_iframe = Dom_html.createIframe Dom_html.document in + Manip.replaceChildren title_container + Tyxml_js.Html5.[ h1 [ txt ex_meta.title] ]; Manip.replaceChildren text_container - Tyxml_js.Html5.[ h1 [ txt ex_meta.title ] ; - Tyxml_js.Of_dom.of_iFrame text_iframe ] ; + [ Tyxml_js.Of_dom.of_iFrame text_iframe ]; Js.Opt.case (text_iframe##.contentDocument) (fun () -> failwith "cannot edit iframe document") diff --git a/static/css/learnocaml_description.css b/static/css/learnocaml_description.css index 2f7260b5c..43db782d9 100644 --- a/static/css/learnocaml_description.css +++ b/static/css/learnocaml_description.css @@ -31,8 +31,9 @@ body { display: flex; flex-direction: column; overflow: hidden; + border: none; } -#learnocaml-exo-tabs > * > h1 { +#learnocaml-exo-tabs h1 { flex: 0 0 auto; background: #222; color: #eee; @@ -43,16 +44,92 @@ body { display: block; font-weight: normal; position: relative; + border-bottom: thin solid #eee; } -#learnocaml-exo-tabs > * > h1:first-child { +#learnocaml-exo-tabs h1:first-child { margin-top: 5px; } -#learnocaml-exo-tabs > * > iframe { +#learnocaml-exo-tabs iframe { border: none; overflow: auto; flex: 1 3 auto ; } -#learnocaml-exo-tab-meta > h1::after { +#learnocaml-exo-tab-meta h1::after { + position: absolute; + left: 0px; bottom: -5px; width: 100%; + content:""; + height:5px; background: pink; + background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0, transparent 100%) +} + +/* ----------------------- iframe --------------------------------*/ + +#learnocaml-exo-tab-text-descr { + position : absolute; + top: 48px; + right : 0px; + left : 0px; + bottom : 0px; + display : flex ; + flex-direction : column; +} + +/* -------------------- Prelude -------------------------------- */ + +#learnocaml-exo-tab-text-prelude { + overflow: hidden; + left: 0; + top: 61px; + z-index: 1002; + border-bottom: thin solid #eee; + width: 100%; +} +#learnocaml-exo-tab-text-prelude > h1 { + position: relative; + flex: 0 0 auto; + background: #222; + color: #eee; + font-size: 20px; + line-height: 22px; + margin: 0; + padding-top: 10px; + padding-bottom: 10px; + display: block; + font-weight: normal; + z-index: 1005; + width: 100%; + text-align: center; +} +#learnocaml-exo-tab-text-prelude > h1:first-child { + margin-top: 0; +} +#learnocaml-exo-tab-text-prelude > h1 > button { + float: right; + border: none; + border-left: 1px #eee solid; + color: #eee; + padding-top: 10px; + padding-bottom: 10px; + margin-top: -10px; + margin-bottom: -10px; + font-size: 20px; + line-height: 22px; + z-index: 1006; + width: 20%; + background: #222; +} + +#learnocaml-exo-tab-text-prelude > pre.toplevel-code { + flex: 0 1 auto; + height: 150px; + max-height: 150px; + background: #666; + margin: 0; + overflow: auto; + width: 100%; + position: absolute; +} +#learnocaml-exo-tab-text-prelude > h1::after { position: absolute; left: 0px; bottom: -5px; width: 100%; content:""; @@ -60,6 +137,8 @@ body { background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0, transparent 100%) } + + /* BEGIN excerpt from learnocaml_exercise.css */ .learnocaml-exo-meta-category ~ .exercise + .exercise { @@ -191,9 +270,9 @@ body { #learnocaml-exo-tab-text { position: relative; flex-grow: 4; - border-right: #222 2px solid; + border-right: none; overflow-y: auto; - } + } #learnocaml-exo-tab-meta { position: relative; flex-grow: 1; diff --git a/static/description.html b/static/description.html index 227b8a8e7..2efe7ea44 100644 --- a/static/description.html +++ b/static/description.html @@ -6,8 +6,9 @@ Learn OCaml by OCamlPro - Description - + + @@ -34,7 +35,11 @@
-
+
+
+
+
+