aboutsummaryrefslogtreecommitdiff
path: root/editor/editor.ml
blob: 1a34dfc38329ab00426d67282a4a0e70764ab154 (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
119
120
121
122
123
124
125
open Brr
module PM = Prosemirror
module Js = Js_of_ocaml.Js

(** 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


(** [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 -> (App.events, State.t) Application.t
  = App.update

let app id content =

  (* This event is used in the pop process. The sender is given to the
     subroutine in order to track the window closing *)
  let event, sender = Note.E.create () in

  (* Check the pre-requisite *)
  let events_opt = Actions.populate_menu () in
  match (Jv.is_none id), (Jv.is_none content), events_opt with
  | false, false, Some btn_events ->

    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.{ editable = true
            ; view
            ; last_backup
            ; page_id

            ; window = []
            ; pm
            }
    in

    let app_state = Application.run
        ~eq:State.eq
        (App.update sender)
        init_state
        (Note.E.select
           [ Brr_note.Evr.on_el Ev.focusout (fun _ -> App.StoreEvent) editor
           ; Note.E.map (fun () -> App.DeleteEvent)  btn_events.Actions.delete
           ; Note.E.map (fun () -> App.AddEvent)     btn_events.Actions.add
           ; Note.E.map (fun v  -> App.LoadEvent v)  btn_events.Actions.redirect
           ; Note.E.map (fun v  -> App.CloseEvent v) event
           ]) in

    let () =
      Note.S.log app_state (fun _ -> ())
      |> Note.Logr.hold in

    ()

  | _, _, _ ->
    Console.(error [str "No element with id '%s' '%s' found"; id ; content])

let () =

  let open Jv in
  let editor = obj
      [| "attach_prosemirror", (repr app)
      |] in

  set global "editor" editor