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/actions.ml | 22 +++------- editor/editor.ml | 124 ++++++++++++++++++++++++++---------------------------- 2 files changed, 67 insertions(+), 79 deletions(-) (limited to 'editor') diff --git a/editor/actions.ml b/editor/actions.ml index c02584f..3b17dae 100755 --- a/editor/actions.ml +++ b/editor/actions.ml @@ -3,7 +3,7 @@ open Brr open Brr_note type button_actions = - { edit : El.t * (unit Note.event) + { delete : El.t * (unit Note.event) } let populate_menu () = @@ -13,21 +13,21 @@ let populate_menu () = let () = Blog.Sidebar.clean element in let uri = Brr.Window.location Brr.G.window in - let edit_button = El.button + 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-pen") + ; class' (Jstr.v "fa-trash") ] ] in - let edit_event = + let delete_event = Evr.on_el Ev.click Evr.unit - edit_button in + delete_button in let pages = @@ -52,7 +52,6 @@ let populate_menu () = ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-home") ] ] - ; edit_button ; El.button ~at:At.[class' (Jstr.v "action-button")] [ El.i @@ -69,14 +68,7 @@ let populate_menu () = ; class' (Jstr.v "fa-2x") ; class' (Jstr.v "fa-download") ] ] - ; 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") ] - ] + ; delete_button ; El.button ~at:At.[class' (Jstr.v "action-button")] [ El.i @@ -92,5 +84,5 @@ let populate_menu () = let () = El.append_children element childs in Some - { edit = (edit_button, edit_event) + { delete = (delete_button, delete_event) } 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