From eb319516fd922ab89b7120a885d1e801fa3f45aa Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Mon, 7 Feb 2022 16:12:05 +0100 Subject: Enjoy the Application pattern --- editor/editor.ml | 124 +++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 64 deletions(-) (limited to 'editor/editor.ml') diff --git a/editor/editor.ml b/editor/editor.ml index 53a6029..fccaa76 100755 --- a/editor/editor.ml +++ b/editor/editor.ml @@ -5,12 +5,15 @@ module Js = Js_of_ocaml.Js (** This is the state for the application *) type state = { editable : bool + ; view : PM.View.editor_view Js.t + ; last_backup: float } type events = - | EditEvent + | DeleteEvent + | StoreEvent -let editor_of_storage +let state_of_storage : PM.t -> Storage.content Js.t -> PM.Model.schema Js.t -> PM.State.editor_state Js.t = fun pm content schema -> Js.Opt.case @@ -27,20 +30,14 @@ let editor_of_storage obj##.schema := Js.some schema; PM.State.fromJSON pm obj page_content) -let update - : (events, state) Application.t - = fun event state -> - match event with - | EditEvent -> - { editable = not state.editable } +(** Create a new editor view -let init_state = - { editable = true - } + [build_view element state] will create the editor and attach it to [element]. +*) let build_view - : El.t -> state Note.S.t -> PM.View.editor_view Js.t * float ref - = fun editor app_state -> + : El.t -> PM.View.editor_view Js.t * float + = fun editor -> let pm = PM.v () in (* Remove all the elements if any *) @@ -70,14 +67,12 @@ let build_view (* 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 = ref @@ Js.Opt.get + 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 := editor_of_storage pm stored_content full_schema; - props##.editable := Js.wrap_callback @@ (fun _state -> - Js.bool ( (Note.S.value app_state).editable) ); + props##.state := state_of_storage pm stored_content full_schema; (* Add the custom nodes *) props##.nodeViews := PM.O.init @@ -90,6 +85,43 @@ let build_view 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 + : (events, state) Application.t + = fun event state -> + match event with + | DeleteEvent -> + state + + | StoreEvent -> + 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.null + val date = Js.some new_date + end in + let save = Storage.save + content_obj + Storage.page_id + ~check:(fun previous_state -> + Js.Opt.case previous_state##.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. *) + date <= state.last_backup)) in + begin match save with + | Ok true -> { state with last_backup = new_date } + | _ -> state + end + let app id content = (* Check the pre-requisite *) @@ -98,63 +130,27 @@ let app id content = | false, false, Some btn_events -> let editor:El.t = Jv.Id.of_jv id in + let view, last_backup = build_view editor in + + let init_state = + { editable = true + ; view + ; last_backup + } + in + let app_state = Application.run update init_state (Note.E.select - [ Note.E.map (fun () -> EditEvent) (snd btn_events.Actions.edit) + [ Note.E.map (fun () -> DeleteEvent) (snd btn_events.Actions.delete) + ; Brr_note.Evr.on_el Ev.focusout (fun _ -> StoreEvent) editor ]) in let () = Note.S.log app_state (fun _ -> ()) |> Note.Logr.hold in - (** Map active style of the button with the state *) - let () = - Brr_note.Elr.def_class - (Jstr.v "active") - (Note.S.map (fun s -> s.editable) app_state) - (fst btn_events.Actions.edit) in - - let view, last_backup = build_view editor app_state in - - (* Attach an event on focus out *) - let _ = Brr_note.Evr.on_el - (Ev.focusout) - (fun _ -> - let new_date = (new%js Js.date_now)##getTime in - let content_obj = object%js - val content = Js.some @@ Jv.Id.to_jv (view##.state##toJSON ()) - val title = Js.null - val date = Js.some new_date - end in - let save = Storage.save - content_obj - Storage.page_id - ~check:(fun previous_state -> - Js.Opt.case previous_state##.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. *) - date <= !last_backup)) in - match save with - | Ok true -> last_backup := new_date - | _ -> ()) - editor in - - let ev = - Note.E.map - (fun _ -> view##dispatch view##.state##.tr) - (Note.S.changes (Note.S.map (fun s -> s.editable) app_state)) in - let () = - Note.E.log ev (fun _ -> ()) - |> Option.iter Note.Logr.hold in () | _, _, _ -> -- cgit v1.2.3