summaryrefslogtreecommitdiff
path: root/editor/editor.ml
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2022-02-07 16:40:45 +0100
committerSébastien Dailly <sebastien@dailly.me>2022-02-07 16:43:33 +0100
commit8d23a029c57be92a7aed0f18d9fcf1c931c1038e (patch)
tree5bce8907c420b171de9f49679045723aad03e247 /editor/editor.ml
parent6f1b152a6927171b0c0bfed207307ed1bac1900d (diff)
Reformat
Diffstat (limited to 'editor/editor.ml')
-rwxr-xr-xeditor/editor.ml325
1 files changed, 184 insertions, 141 deletions
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