open StdLabels open Brr open Brr_note module App = Editor_app module Js = Js_of_ocaml.Js (** This is the attribute attached to each link and containing the node id pointed by the link. *) let note_id_attribute = Jstr.v "data-note-id" type t = { ev : App.event Note.event ; childs : El.t list ; ul : El.t ; mutable completed : bool ; delete_button : El.t } let build : Prosemirror.t -> t = fun pm -> let delete_button = El.button ~at:At.[ class' (Jstr.v "action-button") ] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-trash") ] ] and home_button = El.button ~at:At.[ class' (Jstr.v "action-button") ] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-home") ] ] and add_button = El.button ~at:At.[ class' (Jstr.v "action-button") ] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-plus") ] ] and export_button = El.button ~at:At.[class' (Jstr.v "action-button")] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-download") ] ] and load_button = El.button ~at:At.[class' (Jstr.v "action-button")] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-upload") ] ] and cog_button = El.button ~at:At.[class' (Jstr.v "action-button")] [ El.i [] ~at:At.[ class' (Jstr.v "fa") ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-cog") ] ] in (* We are waiting for event inside another event ( form validation inside popup creation. Note.E.join is used here in order to get only te popup validation. *) let delete_event = Note.E.join ( Evr.on_el Ev.click (fun _ -> Delete_page.create ()) delete_button) (* Event on popup creation *) and add_event = Note.E.join ( Evr.on_el Ev.click (fun _ -> Add_page.create ()) add_button) and export_event = Evr.on_el Ev.click (fun _ -> Export.create ()) export_button and import_event = Note.E.join ( Evr.on_el Ev.click (fun _ -> Import.create ()) load_button) and cog_event = Evr.on_el Ev.click (fun _ -> To_markdown.create pm) cog_button in let redirect_handler = (module Load_page.M : App.Event with type t = Load_page.M.t ) in let ul = El.ul [] in (* Wait for a click on an existing page in order to sent the associated event. We compose the resulting event with both : - the home button - the list for all the pages presents in the sidebar We use the bubble property in order to listen only the [ul] element and not the each entry in the list. This way, there is no recursive loop between the redirect_handler and the dynamic generation of elements inside the [ul] node. *) let redirect_event = Note.E.select [ Evr.on_el Ev.click (fun _ -> App.E (None, redirect_handler)) home_button ; Evr.on_el Ev.click (fun ev -> let el = Jv.Id.of_jv @@ Jv.Id.to_jv @@ Ev.target ev in let name = El.at note_id_attribute el in App.E (name, redirect_handler)) ul ] in let childs = [ home_button ; add_button ; export_button ; load_button ; delete_button ; cog_button ; El.hr () ; ul ] in let result_event = Note.E.select [ delete_event ; redirect_event ; add_event ; export_event ; import_event ; cog_event ] in { ev = result_event ; childs ; ul ; delete_button ; completed = false } let get_event : t -> App.event Note.event = fun {ev; _} -> ev (** Collect all the notes in the cache and return them into links. *) let get_notes _ = List.map (State.Storage.get_ids ()) ~f:(fun id -> let name_opt = (State.Storage.load (Some id))##.title in let name = Js.Opt.get name_opt (fun () -> id) in El.li [ El.a ~at:[ At.href (Jstr.v "#") ; At.v note_id_attribute id ] [ El.txt name ] ]) let complete : t -> State.t Note.signal -> El.t list = fun t change -> (* As we register some events, we have to prevent many execution of this function *) let () = if t.completed then raise (Failure "The action panel is already registered") in t.completed <- true; Elr.def_children t.ul (Note.S.map get_notes change); Elr.def_at (Jstr.v "disabled") (Note.S.map (fun state -> match state.State.page_id with | None -> Some Jstr.empty | Some _ -> None) change) t.delete_button; t.childs