open Js_of_ocaml open Brr open Note let storage_key = (Jstr.v "content") (** Save the text into the local storage *) let save_contents : Quill.t -> unit = fun editor -> let storage = Brr_io.Storage.local G.window in let contents = Quill.get_contents editor in Brr_io.Storage.set_item storage storage_key (Json.encode @@ Quill.delta_to_json @@ contents) |> Console.log_if_error ~use:() (** Load the content from the cache storage *) let load_contents : Quill.t -> unit = fun editor -> let storage = Brr_io.Storage.local G.window in Brr_io.Storage.get_item storage storage_key |> Option.iter (fun contents -> Json.decode contents |> Result.map (fun json -> Quill.delta_of_json json |> Quill.set_contents editor ) |> Console.log_if_error ~use:() ) let quill id = begin match (Jv.is_none id) with | true -> Console.(error [str "No element with id '%s' found"; id]) | false -> let options = Quill.options () in J.set options Quill.placeholder (Jstr.v "Nouvelle noteā€¦"); J.set options Quill.theme (Jstr.v "snow"); (* Create the editor with the configuration *) Quill.quill ~options (Jv.Id.of_jv id) |> Result.iter (fun editor -> load_contents editor; let () = Quill.on_text_change editor (fun delta old source -> let _ = delta and _ = old and _ = source in () ) in (* Attach an event on focus out *) let out_event = Brr_note.Evr.on_el (Ev.focusout) (fun _ -> save_contents editor) (Jv.Id.of_jv id) in (* Prevent the event to be garbage collected *) E.log out_event (fun _ -> ()) |> Option.iter Logr.hold ) end let create_new_state pm pm_model pm_state mySchema content = let module PM = Prosemirror in let doc = PM.Model.( DOMParser.parse (DOMParser.from_schema pm_model mySchema) (Jv.Id.of_jv content)) in let props = PM.State.creation_prop () in props##.doc := Js.some doc; props##.plugins := Js.some (PM.example_setup pm mySchema); PM.State.create pm_state props let storage_key = (Jstr.v "editor") let prosemirror id content = begin match (Jv.is_none id), (Jv.is_none content) with | false, false -> let module PM = Prosemirror in let pm = PM.v () in let ( let+ ) o f = Option.iter f o and ( and+ ) a b = match a, b with | Some a, Some b -> Some (a, b) | _ -> None in let+ pm_state = J.get pm PM.state and+ pm_view = J.get pm PM.view and+ pm_model = J.get pm PM.model and+ schema_basic = J.get pm PM.schema_basic and+ schema_list = J.get pm PM.schema_list in let _ = schema_basic and _ = schema_list in let mySchema = Js_of_ocaml.Js.Unsafe.eval_string {|new PM.model.Schema({ nodes: PM.schema_list.addListNodes(PM.schema_basic.schema.spec.nodes, "paragraph block*", "block"), marks: PM.schema_basic.schema.spec.marks })|} in (* Create the initial state *) let storage = Brr_io.Storage.local G.window in let opt_data = Brr_io.Storage.get_item storage storage_key in let state = match opt_data with | None -> create_new_state pm pm_model pm_state mySchema content | Some contents -> (* Try to load from the storage *) begin match Json.decode contents with | Error _ -> create_new_state pm pm_model pm_state mySchema content | Ok json -> Console.(log [Jstr.v "Loading json"]); let history = PM.History.(history pm (history_prop ()) ) in Console.(log [history]); let _ = history in let obj = PM.State.configuration_prop () in obj##.plugins := Js.some (PM.example_setup pm mySchema); obj##.schema := mySchema; PM.State.fromJSON pm_state obj json end in let props = PM.View.direct_editor_props () in props##.dispatchTransaction := (Js.wrap_meth_callback (fun view transaction -> Console.(log [ Jstr.v "Document size went from" ; transaction##.before##.content##.size ]); let state = view##.state##apply transaction in view##updateState state )); props##.state := state; let view = PM.View.editor_view pm_view (Jv.Id.of_jv id) props in view##setProps props; (* Attach an event on focus out *) let _out_event = Brr_note.Evr.on_el (Ev.focusout) (fun _ -> let contents = view##.state##toJSON () in let storage = Brr_io.Storage.local G.window in Brr_io.Storage.set_item storage storage_key (Json.encode @@ contents) |> Console.log_if_error ~use:() ) (Jv.Id.of_jv id) in () | _, _-> Console.(error [str "No element with id '%s' '%s' found"; id ; content]) end let () = let open Jv in let editor = obj [| "attach_quill", (repr quill) ; "attach_prosemirror", (repr prosemirror) |] in set global "editor" editor