aboutsummaryrefslogtreecommitdiff
path: root/editor/plugins/tooltip.ml
blob: 05d56d4cfe9c6e9fa8d8c0859923e3925fd35ebe (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
open StdLabels
open Brr

module Js = Js_of_ocaml.Js
module PM = Prosemirror

(** https://prosemirror.net/examples/tooltip/ *)


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 "popin")
                ]) 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_em =
                   Js.Opt.bind current_stored_marks
                     (fun t -> mark_type##isInSet t) in
                 Js.Opt.case is_em
                   (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 *)
            let start = view##.state##.selection##.from
            and end' = view##.state##.selection##._to in
            Popin.set_position ~start ~end' 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