From 8d23a029c57be92a7aed0f18d9fcf1c931c1038e Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Mon, 7 Feb 2022 16:40:45 +0100 Subject: Reformat --- editor/editor.ml | 325 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 184 insertions(+), 141 deletions(-) (limited to 'editor/editor.ml') diff --git a/editor/editor.ml b/editor/editor.ml index 575e164..d558a7a 100755 --- a/editor/editor.ml +++ b/editor/editor.ml @@ -1,174 +1,217 @@ open Brr module PM = Prosemirror module Js = Js_of_ocaml.Js - module Actions = Editor_actions +let _ = + Js.Unsafe.global ##. PM := + object%js + val commands = Js.Unsafe.js_expr {|require("prosemirror-commands")|} + + val dropcursor = Js.Unsafe.js_expr {|require("prosemirror-dropcursor")|} + + val example_setup_ = + Js.Unsafe.js_expr {|require("prosemirror-example-setup")|} + + val gapcursor = Js.Unsafe.js_expr {|require("prosemirror-gapcursor")|} + + val history = Js.Unsafe.js_expr {|require("prosemirror-history")|} + + val inputrules = Js.Unsafe.js_expr {|require("prosemirror-inputrules")|} + + val keymap = Js.Unsafe.js_expr {|require("prosemirror-keymap")|} + + val menu = Js.Unsafe.js_expr {|require("prosemirror-menu")|} + + val model = Js.Unsafe.js_expr {|require("prosemirror-model")|} + + val schema_basic_ = + Js.Unsafe.js_expr {|require("prosemirror-schema-basic")|} + + val schema_list_ = + Js.Unsafe.js_expr {|require("prosemirror-schema-list")|} + + val state = Js.Unsafe.js_expr {|require("prosemirror-state")|} + + val transform = Js.Unsafe.js_expr {|require("prosemirror-transform")|} + + val view = Js.Unsafe.js_expr {|require("prosemirror-view")|} + end + + +(** Load the js-zip library, with browserify *) +let zip = Js.Unsafe.js_expr {|require("jszip")|} + (** 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 +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 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) + module Store = struct type t = El.t - let process - : t -> State.t -> State.t - = fun title_element state -> - let title = El.prop (El.Prop.value) title_element in + let process : t -> State.t -> State.t = + fun title_element state -> + let title = El.prop El.Prop.value title_element in - let new_date = (new%js Js.date_now)##getTime in - let content_obj = object%js + let new_date = (new%js Js.date_now)##getTime in + let content_obj = + object%js val content = Js.some @@ Jv.Id.to_jv (state.view##.state##toJSON ()) + val title = Js.some title + val date = Js.some new_date - end in - let save = State.Storage.save - content_obj - state.page_id - (* There three date here : - - The actual date at the time we save the note - - The date associated with the note when we loaded it first time - - The date associated with the note at the time we want to update it - - The two last may differ if the note has been updated in another one tab. *) - ~check:(fun ~previous ~update -> - let _ = update in - Js.Opt.case previous##.date - (fun () -> true) - (fun date -> - (* I do not figure how the previous date could be older - than the last backup. It could be either : - - - equal (if we are the only one to update it) - - more recent (if the content has been updated elsewhere) - - but older shoud be a bug. *) - let is_ok = date <= state.last_backup in - if (not is_ok) then ( - let open Console in - log - [ Jstr.v "Last backup date is " - ; new%js Js.date_fromTimeValue state.last_backup - ; Jstr.v " but date is " - ; new%js Js.date_fromTimeValue date] ); - is_ok)) in - begin match save with - | Ok true -> { state with last_backup = new_date } - | Ok false -> - Console.(log [Jstr.v "Didn't save"]); - state - | Error other -> - (* TODO In case of error, notify the user *) - Console.(log [Jstr.v "Couldn't save" ; other]); - state end + in + let save = + State.Storage.save + content_obj + state.page_id + (* There three date here : + - The actual date at the time we save the note + - The date associated with the note when we loaded it first time + - The date associated with the note at the time we want to update it + + The two last may differ if the note has been updated in another one + tab. *) + ~check:(fun ~previous ~update -> + let _ = update in + Js.Opt.case + previous##.date + (fun () -> true) + (fun date -> + (* I do not figure how the previous date could be older + than the last backup. It could be either : + + - equal (if we are the only one to update it) + - more recent (if the content has been updated elsewhere) + + but older shoud be a bug. *) + let is_ok = date <= state.last_backup in + ( if not is_ok + then + let open Console in + log + [ Jstr.v "Last backup date is " + ; new%js Js.date_fromTimeValue state.last_backup + ; Jstr.v " but date is " + ; new%js Js.date_fromTimeValue date + ] ); + is_ok ) ) + in + match save with + | Ok true -> { state with last_backup = new_date } + | Ok false -> + Console.(log [ Jstr.v "Didn't save" ]); + state + | Error other -> + (* TODO In case of error, notify the user *) + Console.(log [ Jstr.v "Couldn't save"; other ]); + state end module App = Editor_app let app id content = - let title_element = Document.find_el_by_id G.document (Jstr.v "title") in (* Check the pre-requisite *) - match title_element, (Jv.is_none id), (Jv.is_none content), Blog.Sidebar.get () with + match + (title_element, Jv.is_none id, Jv.is_none content, Blog.Sidebar.get ()) + with | Some title, false, false, Some sidebar -> - - let () = Blog.Sidebar.clean sidebar in - - 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.init pm view last_backup page_id in - - (* Initialize the buttons actions and get the associated events. - At this point, the HTML element is not yet created, and cannot be - inserted in the document. - *) - let side_elements = Editor_actions.build pm in - let btn_events = Editor_actions.get_event side_elements in - - (* Create the main event loop with all the collected events *) - let app_state = App.run - ~eq:State.eq - init_state - (Note.E.select - [ Brr_note.Evr.on_els Ev.focusout - (fun _ _ -> App.dispatch (module Store) title) - [ editor ; title ] - ; btn_events - ]) in - - (* Get the html element associated with the buttons, and add it in the - page. - - The state event is already created, and can be given in the html - creation in order to update the elements when the state change. - *) - let childs = Editor_actions.complete side_elements app_state in - let () = El.append_children sidebar childs in - let _ = Note.(Logr.hold (S.log app_state (fun _ -> ()))) in - () - + let () = Blog.Sidebar.clean sidebar in + + 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.init pm view last_backup page_id in + + (* Initialize the buttons actions and get the associated events. + At this point, the HTML element is not yet created, and cannot be + inserted in the document. + *) + let side_elements = Editor_actions.build pm in + let btn_events = Editor_actions.get_event side_elements in + + (* Create the main event loop with all the collected events *) + let app_state = + App.run + ~eq:State.eq + init_state + (Note.E.select + [ Brr_note.Evr.on_els + Ev.focusout + (fun _ _ -> App.dispatch (module Store) title) + [ editor; title ] + ; btn_events + ] ) + in + + (* Get the html element associated with the buttons, and add it in the + page. + + The state event is already created, and can be given in the html + creation in order to update the elements when the state change. + *) + let childs = Editor_actions.complete side_elements app_state in + let () = El.append_children sidebar childs in + let _ = Note.(Logr.hold (S.log app_state (fun _ -> ()))) in + () | _ -> - Console.(error [str "No element with id '%s' '%s' found"; id ; content]) + Console.(error [ str "No element with id '%s' '%s' found"; id; content ]) -let () = +let () = let open Jv in - let editor = obj - [| "attach_prosemirror", (repr app) - |] in + let editor = obj [| ("attach_prosemirror", repr app) |] in set global "editor" editor -- cgit v1.2.3