aboutsummaryrefslogtreecommitdiff
path: root/editor/app.ml
blob: aee396a570e400f35b9c66555116b1eacd1ec266 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
open Brr
module PM = Prosemirror
module Js = Js_of_ocaml.Js

type events =
  | DeleteEvent
  | StoreEvent
  | LoadEvent of Jstr.t option
  | AddEvent
  | CloseEvent of Forms.Events.kind option
  | GEvent of Forms.Events.event

let key_of_title
  : Jstr.t -> Jstr.t
  = fun title ->
    title

(** [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 -> (events, State.t) Application.t
  = fun close_sender event state ->
    match event with

    | GEvent (Event (t, (module Handler))) ->
      Handler.on_close t state

    | AddEvent ->
      let title = Jstr.v "Nouvelle page" in
      let popup = Ui.popup
          ~title
          ~form:(Some (Forms.Add_page.create ()))
          close_sender in
      { state with window = popup::state.window}

    | DeleteEvent ->
      begin match state.page_id with
        | None -> state
        | Some page_id ->
          let title = Jstr.v "Confirmation" in
          let popup = Ui.popup
              ~title
              ~form:(Some (Forms.Delete_page.create page_id))
              close_sender in
          { state with window = popup::state.window}
      end

    | CloseEvent res ->

      let state = match state.window with
        | []     -> { state with window = [] }
        | el::tl -> El.remove el
                  ; { state with window = tl } in

      (* The actions is confirmed by the user. Handle the form result *)
      begin match res with
        (* Delete the current page, then load the home page *)
        | Some (Forms.Delete_page.DeletePage id) ->
          State.Storage.delete (fun () -> Some id);
          let json = State.Storage.load None in
          State.load_page None state json
        (* Add a new page *)
        | Some (Forms.Add_page.AddPage {title}) ->
          let page_id = key_of_title title in
          let new_date = (new%js Js.date_now)##getTime in
          let content_obj = object%js
            val content = Js.null
            val title = Js.some title
            val date = Js.some new_date
          end in
          State.load_page (Some page_id) state content_obj

        | _ -> state
      end

    | StoreEvent ->

      let title_element = Document.find_el_by_id G.document (Jstr.v "title") in
      let content = Option.map
          (fun el -> El.prop (El.Prop.value) el)
          title_element in

      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.Opt.option content
        val date = Js.some new_date
      end in
      let save = State.Storage.save
          content_obj
          state.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 }
        | other ->
          (* TODO In case of error, notify the user *)
          Console.(log [other]);
          state
      end

    | LoadEvent page_id ->
      let json = State.Storage.load page_id in
      State.load_page page_id state json