diff options
Diffstat (limited to 'editor/plugins')
-rwxr-xr-x | editor/plugins/link_editor.ml | 216 | ||||
-rwxr-xr-x | editor/plugins/plugins.ml | 209 |
2 files changed, 203 insertions, 222 deletions
diff --git a/editor/plugins/link_editor.ml b/editor/plugins/link_editor.ml index 9bfdfd4..9fcfc51 100755 --- a/editor/plugins/link_editor.ml +++ b/editor/plugins/link_editor.ml @@ -1,127 +1,103 @@ open Brr - module Js = Js_of_ocaml.Js module PM = Prosemirror -let link_edit - : PM.View.editor_view Js.t -> < .. > Js.t - = fun view -> - - let popin = El.div [] - ~at:At.([class' (Jstr.v "popin")]) in - - El.set_inline_style El.Style.display (Jstr.v "none") popin; - - let parent = Jv.(Id.of_jv @@ get (Jv.Id.to_jv view##.dom) "parentNode") in - let () = El.append_children parent [popin] in - - let hide - : unit -> unit - = fun () -> - El.set_inline_style El.Style.display (Jstr.v "none") popin - in - - let update - : PM.View.editor_view Js.t -> PM.State.editor_state Js. t Js.opt -> unit - = fun view _state_opt -> - - let state = view##.state in - Js.Opt.case (state##.doc##nodeAt (view##.state##.selection##._to)) - (fun () -> hide ()) - (fun node -> - (* Check if we are editing a link *) - match PM.O.get state##.schema##.marks "link" with - | None -> () - | Some link_type -> - let is_present = link_type##isInSet node##.marks in - Js.Opt.case - is_present - (fun () -> hide ()) - (fun mark -> - (* Get the node's bounding position and display the popin *) - let position = state##.doc##resolve - (view##.state##.selection##._to) in - let start = position##start Js.null - and end' = position##_end Js.null in - - Popin.set_position - ~start - ~end' - view popin; - - (* Extract the value from the attribute *) - let attrs = mark##.attrs in - let href_opt = PM.O.get attrs "href" in - let href_value = Option.value - ~default:Jstr.empty - href_opt - in - - (* Create the popin content *) - let a = El.a - ~at:At.[ href href_value ] - [ El.txt href_value ] in - - let entry = Popin.build_field a - (fun new_value -> - (* The function is called when the user validate - the change in the popi. We create a new - transaction in the document by replacing the - mark with the new one. *) - if not (Jstr.equal new_value href_value) then ( - - (* Create a new attribute object for the mark in - order to keep history safe *) - let attrs' = PM.O.init - [| "href", new_value |] in - - Option.iter - (fun v -> PM.O.set attrs' "title" v) - (PM.O.get attrs "title"); - - let mark' = state##.schema##mark_fromType - link_type - (Js.some attrs') in - (* Create a transaction which update the - mark with the new value *) - view##dispatch - state - ##.tr - ##(removeMark - ~from:start - ~to_:end' - mark) - ##(addMark - ~from:start - ~to_:end' - mark') - ); - true - - ) in - - - El.set_children popin - [ entry.field - ; entry.button ]; - - )) - - and destroy () = El.remove popin in - +let link_edit : PM.View.editor_view Js.t -> < .. > Js.t = + fun view -> + let popin = El.div [] ~at:At.[ class' (Jstr.v "popin") ] in + + El.set_inline_style El.Style.display (Jstr.v "none") popin; + + let parent = Jv.(Id.of_jv @@ get (Jv.Id.to_jv view##.dom) "parentNode") in + let () = El.append_children parent [ popin ] in + + let hide : unit -> unit = + fun () -> El.set_inline_style El.Style.display (Jstr.v "none") popin + in + + let update : + PM.View.editor_view Js.t -> PM.State.editor_state Js.t Js.opt -> unit = + fun view _state_opt -> + let state = view##.state in + Js.Opt.case + (state##.doc##nodeAt view##.state##.selection##._to) + (fun () -> hide ()) + (fun node -> + (* Check if we are editing a link *) + match PM.O.get state##.schema##.marks "link" with + | None -> () + | Some link_type -> + let is_present = link_type##isInSet node##.marks in + Js.Opt.case + is_present + (fun () -> hide ()) + (fun mark -> + (* Get the node's bounding position and display the popin *) + let position = + state##.doc##resolve view##.state##.selection##._to + in + let start = position##start Js.null + and end' = position##_end Js.null in + + Popin.set_position ~start ~end' view popin; + + (* Extract the value from the attribute *) + let attrs = mark##.attrs in + let href_opt = PM.O.get attrs "href" in + let href_value = Option.value ~default:Jstr.empty href_opt in + + (* Create the popin content *) + let a = El.a ~at:At.[ href href_value ] [ El.txt href_value ] in + + let entry = + Popin.build_field a (fun new_value -> + (* The function is called when the user validate + the change in the popi. We create a new + transaction in the document by replacing the + mark with the new one. *) + if not (Jstr.equal new_value href_value) + then ( + (* Create a new attribute object for the mark in + order to keep history safe *) + let attrs' = PM.O.init [| ("href", new_value) |] in + + Option.iter + (fun v -> PM.O.set attrs' "title" v) + (PM.O.get attrs "title"); + + let mark' = + state##.schema##mark_fromType + link_type + (Js.some attrs') + in + (* Create a transaction which update the + mark with the new value *) + view##dispatch + state + ##. tr + ## (removeMark ~from:start ~to_:end' mark) + ## (addMark ~from:start ~to_:end' mark') ); + true ) + in + + El.set_children popin [ entry.field; entry.button ] ) ) + and destroy () = El.remove popin in + + object%js + val update = Js.wrap_callback update + + val destroy = Js.wrap_callback destroy + end + + +let plugin : PM.t -> PM.State.plugin Js.t = + fun t -> + let state = Jv.get (Jv.Id.to_jv t) "state" in + + let params = object%js - val update = Js.wrap_callback update - val destroy= Js.wrap_callback destroy + val view = fun view -> link_edit view end + in -let plugin - : PM.t -> PM.State.plugin Js.t - = fun t -> - let state = Jv.get (Jv.Id.to_jv t) "state" in - - let params = object%js - val view = (fun view -> link_edit view) - end in - - Jv.new' (Jv.get state "Plugin") [| Jv.Id.to_jv params |] - |> Jv.Id.of_jv + Jv.new' (Jv.get state "Plugin") [| Jv.Id.to_jv params |] |> Jv.Id.of_jv diff --git a/editor/plugins/plugins.ml b/editor/plugins/plugins.ml index 3a92df8..51b761c 100755 --- a/editor/plugins/plugins.ml +++ b/editor/plugins/plugins.ml @@ -1,131 +1,137 @@ module Js = Js_of_ocaml.Js module PM = Prosemirror - module Footnotes = Footnotes (** Commands *) -let change_level - : PM.t -> PM.Model.resolved_pos Js.t -> int -> (int -> bool) -> PM.Commands.t - = fun pm res incr pred state dispatch -> - let parent = res##.parent in - let attributes = parent##.attrs in - - let current_level = if Jv.is_none attributes##.level then - 0 - else - attributes##.level in - let t, props = match pred current_level with - | false -> +let change_level : + PM.t -> PM.Model.resolved_pos Js.t -> int -> (int -> bool) -> PM.Commands.t + = + fun pm res incr pred state dispatch -> + let parent = res##.parent in + let attributes = parent##.attrs in + + let current_level = + if Jv.is_none attributes##.level then 0 else attributes##.level + in + let t, props = + match pred current_level with + | false -> ( PM.O.get state##.schema##.nodes "heading" - , Js.some (object%js - val level = current_level + incr - end)) - | true -> - ( PM.O.get state##.schema##.nodes "paragraph" - , Js.null) in - match t with - | None -> Js._false - | Some t -> + , Js.some + (object%js + val level = current_level + incr + end ) ) + | true -> + (PM.O.get state##.schema##.nodes "paragraph", Js.null) + in + match t with + | None -> + Js._false + | Some t -> PM.Commands.set_block_type pm t props state dispatch + (** Increase the title level by one when pressing # at the begining of a line *) let handle_sharp pm state dispatch = - - let res = PM.State.selection_to (state##.selection) in + let res = PM.State.selection_to state##.selection in match Js.Opt.to_option res##.nodeBefore with - | Some _ -> Js._false - | None -> (* Line start *) - begin match Jstr.to_string res##.parent##._type##.name with - | "heading" -> + | Some _ -> + Js._false + | None -> + (* Line start *) + ( match Jstr.to_string res##.parent##._type##.name with + | "heading" -> change_level pm res 1 (fun x -> x > 5) state dispatch - | "paragraph" -> - begin match PM.O.get state##.schema##.nodes "heading" with - | None -> Js._false - | Some t -> - let props = Js.some (object%js - val level = 1 - end) in - PM.Commands.set_block_type pm t props state dispatch - end - | _ -> Js._false - end + | "paragraph" -> + ( match PM.O.get state##.schema##.nodes "heading" with + | None -> + Js._false + | Some t -> + let props = + Js.some + (object%js + val level = 1 + end ) + in + PM.Commands.set_block_type pm t props state dispatch ) + | _ -> + Js._false ) -let handle_backspace pm state dispatch = - let res = PM.State.selection_to (state##.selection) in +let handle_backspace pm state dispatch = + let res = PM.State.selection_to state##.selection in match Js.Opt.to_option res##.nodeBefore with - | Some _ -> Js._false - | None -> (* Line start *) - begin match Jstr.to_string res##.parent##._type##.name with - | "heading" -> change_level pm res (-1) (fun x -> x <= 1) state dispatch - | _ -> Js._false - end - - -let toggle_mark - : Js.regExp Js.t -> PM.t -> string -> PM.InputRule.input_rule Js.t - = fun regExp pm mark_type_name -> - PM.InputRule.create pm - regExp - ~fn:(Js.wrap_callback @@ fun (state:PM.State.editor_state Js.t) _ ~from ~to_ -> - match PM.O.get state##.schema##.marks mark_type_name with - | None -> Js.null - | Some mark_type -> - - let m = state##.schema##mark_fromType mark_type Js.null in - - (* Delete the markup code *) - let tr = (state##.tr)##delete ~from ~to_ in - - (* Check if the mark is active at the position *) - let present = Js.Opt.bind - (PM.State.cursor (tr##.selection)) - (fun resolved -> - Js.Opt.map - (mark_type##isInSet (resolved##marks ())) - (fun _ -> resolved) - ) in - Js.Opt.case present - (fun () -> - let tr = tr##addStoredMark m in - Js.some @@ tr) - (fun _resolved -> - let tr = tr##removeStoredMark_mark m in - Js.some tr)) + | Some _ -> + Js._false + | None -> + (* Line start *) + ( match Jstr.to_string res##.parent##._type##.name with + | "heading" -> + change_level pm res (-1) (fun x -> x <= 1) state dispatch + | _ -> + Js._false ) + + +let toggle_mark : + Js.regExp Js.t -> PM.t -> string -> PM.InputRule.input_rule Js.t = + fun regExp pm mark_type_name -> + PM.InputRule.create + pm + regExp + ~fn: + ( Js.wrap_callback + @@ fun (state : PM.State.editor_state Js.t) _ ~from ~to_ -> + match PM.O.get state##.schema##.marks mark_type_name with + | None -> + Js.null + | Some mark_type -> + let m = state##.schema##mark_fromType mark_type Js.null in + + (* Delete the markup code *) + let tr = state##.tr##delete ~from ~to_ in + + (* Check if the mark is active at the position *) + let present = + Js.Opt.bind + (PM.State.cursor tr##.selection) + (fun resolved -> + Js.Opt.map + (mark_type##isInSet (resolved##marks ())) + (fun _ -> resolved) ) + in + Js.Opt.case + present + (fun () -> + let tr = tr##addStoredMark m in + Js.some @@ tr ) + (fun _resolved -> + let tr = tr##removeStoredMark_mark m in + Js.some tr ) ) + let input_rule pm = + let bold = toggle_mark (new%js Js.regExp (Js.string "\\*\\*$")) pm "strong" + and em = toggle_mark (new%js Js.regExp (Js.string "//$")) pm "em" in - let bold = - toggle_mark - (new%js Js.regExp (Js.string "\\*\\*$")) - pm - "strong" - and em = - toggle_mark - (new%js Js.regExp (Js.string "//$")) - pm - "em" in + PM.InputRule.to_plugin pm (Js.array [| bold; em |]) - PM.InputRule.to_plugin pm - (Js.array [| bold; em |]) let default pm schema = - - (** Load the history plugin *) - let _ = PM.History.(history pm (history_prop ()) ) in + (* Load the history plugin *) + let _ = PM.History.(history pm (history_prop ())) in let props = PM.Example.options schema in - props##.menuBar := Js.some Js._true; - props##.floatingMenu := Js.some Js._true; - props##.menuContent := (Footnotes.build_menu pm schema)##.fullMenu; + props##.menuBar := Js.some Js._true ; + props##.floatingMenu := Js.some Js._true ; + props##.menuContent := (Footnotes.build_menu pm schema)##.fullMenu ; let setup = PM.Example.example_setup pm props in let keymaps = - PM.Keymap.keymap pm - [| "Backspace", (handle_backspace pm) - ; "#", (handle_sharp pm) - |] in + PM.Keymap.keymap + pm + [| ("Backspace", handle_backspace pm); ("#", handle_sharp pm) |] + in (* Add the custom keymaps in the list *) let _ = setup##unshift keymaps in @@ -133,5 +139,4 @@ let default pm schema = let _ = setup##push (Tooltip.bold_plugin pm) in let _ = setup##push (Link_editor.plugin pm) in - Js.some setup |