summaryrefslogtreecommitdiff
path: root/editor/popin.ml
blob: 63dcad17c4e43e67712a43c6224f78b5a828386c (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
open Brr
module Js = Js_of_ocaml.Js
module PM = Prosemirror

type binded_field =
  { field: El.t
  ; button: El.t
  }

(** Set the element position just above the selection  *)
let set_position
  : start:int -> end':int -> PM.View.editor_view Js.t -> El.t -> unit
  = fun ~start ~end' view el ->
    El.set_inline_style El.Style.display (Jstr.v "") el;

    (* These are in screen coordinates *)
    let start = view##coordsAtPos start Js.null
    and end' = view##coordsAtPos end' Js.null in
    let offsetParent = Jv.(Id.of_jv @@ get (Jv.Id.to_jv el) "offsetParent") in

    (* The box in which the tooltip is positioned, to use as base *)
    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

    (* Find a center-ish x position from the selection endpoints (when
       crossing lines, end may be more to the left) *)
    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

(** Build a button which allow to activate or desactivate the given Element.

    The function f is called when the user validate the input.

*)
let build_field
  : El.t -> (Jstr.t -> bool) -> binded_field
  = fun field f ->

    let button_content =
      [ El.i []
          ~at:At.[ class' (Jstr.v "fas")
                 ; class' (Jstr.v "fa-pen") ]
      ] in

    let button = El.button
        button_content
    in

    Ev.listen Ev.click
      (fun _ ->
         match El.at (Jstr.v "contenteditable") field with
         | Some value when (Jstr.equal value (Jstr.v "true")) ->
           let new_value = El.prop
               (El.Prop.jstr (Jstr.v "textContent"))
               field in
           begin match f new_value with
             | true ->
               El.set_at (Jstr.v "contenteditable") None field;
               El.set_children button button_content
             | false -> ()
           end
         | _ ->
           El.set_at (Jstr.v "contenteditable")
             (Some (Jstr.v "true")) field;
           El.set_children button
             [ El.i
                 ~at:At.[ class' (Jstr.v "fas")
                        ; class' (Jstr.v "fa-check") ]
                 []
             ]
      )
      (El.as_target button);

    { field
    ; button = button
    }