open Brr module PM = Prosemirror module Js = Js_of_ocaml.Js (** Create a new editor view [build_view element state] will create the editor and attach it to [element]. *) let build_view : PM.t -> Jstr.t option -> El.t -> PM.View.editor_view Js.t * float = fun pm page_id editor -> (* Remove all the elements if any *) El.set_children editor []; (* TODO This could be improved, instead of creating a new schema, just fetch the node and marks from the plungin *) let custom_schema = Plugins.Footnotes.footnote_schema pm (PM.SchemaBasic.schema pm) in (* Recreate the full schema by adding all the nodes and marks from the plugings *) let specs = PM.Model.schema_spec (PM.SchemaList.add_list_nodes pm (custom_schema##.spec##.nodes) (Jstr.v "paragraph block*") (Some (Jstr.v "block"))) (Some custom_schema##.spec##.marks) None in let full_schema = PM.Model.schema pm specs in let stored_content = State.Storage.load page_id in (* This variable contains the last update time, either because it is stored, or because it is the date where we create the first page. *) let last_backup = Js.Opt.get stored_content##.date (fun () -> (new%js Js.date_now)##getTime) in let props = PM.View.direct_editor_props () in props##.state := State.state_of_storage pm stored_content full_schema; (* Add the custom nodes *) props##.nodeViews := PM.O.init [| ( "footnote", (Plugins.Footnotes.footnote_view pm)) |]; let view = PM.View.editor_view pm editor props in view, last_backup (** [update] is the event loop. The function take a new event, and apply it to the current state. *) let update : 'a option Note.E.send -> (App.events, State.t) Application.t = App.update let app id content = (* This event is used in the pop process. The sender is given to the subroutine in order to track the window closing *) let event, sender = Note.E.create () in (* Check the pre-requisite *) let events_opt = Actions.populate_menu () in match (Jv.is_none id), (Jv.is_none content), events_opt with | false, false, Some btn_events -> let pm = PM.v () in let editor:El.t = Jv.Id.of_jv id in (* Load the cache for the given page *) let page_id = State.Storage.page_id () in let view, last_backup = build_view pm page_id editor in let init_state = State.{ editable = true ; view ; last_backup ; page_id ; window = [] ; pm } in let app_state = Application.run ~eq:State.eq (App.update sender) init_state (Note.E.select [ Brr_note.Evr.on_el Ev.focusout (fun _ -> App.StoreEvent) editor ; Note.E.map (fun () -> App.DeleteEvent) btn_events.Actions.delete ; Note.E.map (fun () -> App.AddEvent) btn_events.Actions.add ; Note.E.map (fun v -> App.LoadEvent v) btn_events.Actions.redirect ; Note.E.map (fun v -> App.CloseEvent v) event ]) in let () = Note.S.log app_state (fun _ -> ()) |> Note.Logr.hold in () | _, _, _ -> Console.(error [str "No element with id '%s' '%s' found"; id ; content]) let () = let open Jv in let editor = obj [| "attach_prosemirror", (repr app) |] in set global "editor" editor