blob: 43c345f9542918acdb432c417f07914249d88d1d (
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
|
open StdLabels
open Js_of_ocaml
open Brr
module PM = Prosemirror
(** https://prosemirror.net/examples/tooltip/ *)
(** Set the element position just above the selection *)
let set_position
: PM.View.editor_view Js.t -> El.t -> unit
= fun view el ->
El.set_inline_style El.Style.display (Jstr.v "") el;
let start = view##coordsAtPos (view##.state##.selection##.from) Js.null
and end' = view##coordsAtPos (view##.state##.selection##._to) Js.null in
let offsetParent = Jv.(Id.of_jv @@ get (Jv.Id.to_jv el) "offsetParent") in
let box = Jv.(Id.of_jv @@ call (Jv.Id.to_jv offsetParent) "getBoundingClientRect" [||]) in
let box_left = Jv.(Id.of_jv @@ get (Jv.Id.to_jv box) "left") in
let box_bottom = Jv.(Id.of_jv @@ get (Jv.Id.to_jv box) "bottom") in
let left = (start##.left +. end'##.left) /. 2. in
El.set_inline_style (Jstr.v "left")
Jstr.( (of_float ( left -. box_left )) + (v "px") )
el;
El.set_inline_style (Jstr.v "bottom")
Jstr.( (of_float ( box_bottom -. start##.top )) + (v "px") )
el
let boldtip
: PM.View.editor_view Js.t -> < .. > Js.t
= fun view ->
(* Create the element which will be displayed over the editor *)
let tooltip = El.div []
~at:At.([class' (Jstr.v "tooltip")]) in
El.set_inline_style El.Style.display (Jstr.v "none") tooltip;
let parent = Jv.(Id.of_jv @@ get (Jv.Id.to_jv view##.dom) "parentNode") in
let () = El.append_children parent [tooltip] in
let update
: PM.View.editor_view Js.t -> PM.State.editor_state Js. t Js.opt -> unit
= fun view state_opt ->
(* Compare the previous and actual state. If the stored marks are the
same, just return *)
let state = view##.state in
let previous_stored_marks =
Js.Opt.bind state_opt (fun state -> state##.storedMarks)
|> Js.Opt.to_option
and current_stored_marks = state##.storedMarks in
let same = match previous_stored_marks, Js.Opt.to_option current_stored_marks with
| Some arr1, Some arr2 ->
Js_lib.Array.compare arr1 arr2 ~f:(fun v1 v2 -> v1##eq v2)
| None, None -> Js._true
| _, _ -> Js._false in
if same <> Js._true then
let is_bold = Option.bind (PM.O.get state##.schema##.marks "strong")
(fun mark_type ->
let is_strong =
Js.Opt.bind current_stored_marks
(fun t -> mark_type##isInSet t) in
Js.Opt.case is_strong
(fun () -> None)
(fun _ -> Some (Jstr.v "gras"))) in
let is_em = Option.bind (PM.O.get state##.schema##.marks "em")
(fun mark_type ->
let is_strong =
Js.Opt.bind current_stored_marks
(fun t -> mark_type##isInSet t) in
Js.Opt.case is_strong
(fun () -> None)
(fun _ -> Some (Jstr.(v "emphase")))) in
let marks = List.filter_map [is_bold; is_em] ~f:(fun x -> x) in
match marks with
| [] -> El.set_inline_style El.Style.display (Jstr.v "none") tooltip
| _ ->
(* The mark is present, add in the content *)
set_position view tooltip;
El.set_prop
(El.Prop.jstr (Jstr.v "textContent"))
(Jstr.concat marks ~sep:(Jstr.v ", "))
tooltip
and destroy () = El.remove tooltip in
object%js
val update = Js.wrap_callback update
val destroy= Js.wrap_callback destroy
end
let bold_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 -> boldtip view)
end in
Jv.new' (Jv.get state "Plugin") [| Jv.Id.to_jv params |]
|> Jv.Id.of_jv
|