@@ -27,88 +27,109 @@ open Js_of_ocaml]
2727
2828let % client display ?(container_a = [a_class [" ot-tip-container" ]])
2929 ?(filter_a = [a_class [" ot-tip-filter" ]])
30- ?(side : [`Center | `Left | `Right] = `Center )
30+ ?(position :
31+ [`Forced_top | `Top | `Ratio of float | `Bottom | `Forced_bottom ] =
32+ `Ratio 0.5 ) ?(side : [`Center | `Left | `Right] = `Center )
3133 ~(origin : Dom_html.element Js.t ) ?(onopen = fun _ _ -> () )
3234 ?(onclose = fun _ _ -> () )
3335 ~(content :
3436 (unit -> unit )
3537 -> [< Html_types. div_content_fun > `Div ] Eliom_content.Html. elt list ) ()
3638 =
3739 let close = ref @@ fun () -> () in
38- let b = origin in
3940 let container =
4041 D. div ~a: container_a
4142 @@ (div ~a: [a_class [" ot-tip-src" ]] [] :: content (fun () -> ! close () ))
4243 in
43- let m = To_dom. of_element container in
44- let mb = b##getBoundingClientRect in
45- let w = mb##.right -. mb##.left in
46- let bb = b##getBoundingClientRect in
47- let top = int_of_float bb##.top in
48- let bottom =
49- Dom_html. document##.documentElement##.clientHeight
50- - int_of_float bb##.bottom
44+ let container_elt = To_dom. of_element container in
45+ let d_height =
46+ float
47+ @@ Js.Optdef. get Dom_html. window##.innerHeight
48+ @@ fun () -> Dom_html. document##.documentElement##.clientHeight
5149 in
52- let left = int_of_float bb##.left in
53- let right =
54- Dom_html. document##.documentElement##.clientWidth - int_of_float bb##.right
50+ let d_width =
51+ float
52+ @@ Js.Optdef. get Dom_html. window##.innerWidth
53+ @@ fun () -> Dom_html. document##.documentElement##.clientWidth
5554 in
55+ let o_bounds = origin##getBoundingClientRect in
56+ let o_left = o_bounds##.left in
57+ let o_right = o_bounds##.right in
58+ let o_to_right = d_width -. o_right in
59+ let o_top = o_bounds##.top in
60+ let o_to_top = d_height -. o_top in
61+ let o_bottom = o_bounds##.bottom in
62+ let o_to_bottom = d_height -. o_bottom in
63+ let o_width = o_right -. o_left in
64+ let o_center_to_left = (o_right +. o_left) /. 2. in
65+ let o_center_to_right = d_width -. o_center_to_left in
66+ let container_ready = Ot_nodeready. nodeready container_elt in
67+ let when_container_ready get_from_container use_it =
68+ Lwt. (async @@ fun () -> container_ready > |= get_from_container > |= use_it)
69+ in
70+ let get_c_height () = float container_elt##.offsetHeight in
71+ let get_half_c_width () = float (container_elt##.offsetWidth / 2 ) in
72+ let c_style = container_elt##.style in
5673 let print_px x = Js. string (Printf. sprintf " %gpx" x) in
57- m##.style##.minWidth := print_px w;
58- (if top < bottom
59- then (
60- let top = print_px bb##.bottom in
61- m##.style##.top := top;
62- m##.classList##add (Js. string " ot-tip-top" ))
63- else
64- let bottom =
65- print_px
66- (float_of_int Dom_html. document##.documentElement##.clientHeight
67- -. bb##.top)
68- in
69- m##.style##.bottom := bottom;
70- m##.classList##add (Js. string " ot-tip-bottom" ));
74+ let c_add_class class_ = Manip.Class. add container class_ in
75+ c_style##.minWidth := print_px o_width;
76+ let put_on_top () =
77+ c_style##.top := print_px 0. ;
78+ c_add_class " ot-tip-bottom"
79+ in
80+ let put_c_below_o () =
81+ c_style##.top := print_px o_bottom;
82+ c_add_class " ot-tip-top"
83+ in
84+ let put_c_above_o () =
85+ c_style##.bottom := print_px o_to_top;
86+ c_add_class " ot-tip-bottom"
87+ in
88+ let when_container_ready_and_in f =
89+ when_container_ready get_c_height @@ fun c_height ->
90+ let enough_space_below_o = c_height < o_to_bottom in
91+ let enough_space_above_o = c_height < o_top in
92+ match enough_space_below_o, enough_space_above_o with
93+ | false , false -> put_on_top ()
94+ | false , true -> put_c_above_o ()
95+ | true , false -> put_c_below_o ()
96+ | true , true -> f ()
97+ in
98+ (match position with
99+ | `Forced_top -> put_c_above_o ()
100+ | `Top -> when_container_ready_and_in put_c_above_o
101+ | `Ratio r ->
102+ when_container_ready_and_in (fun () ->
103+ if (1. -. r) *. o_top < r *. o_to_bottom
104+ then put_c_below_o ()
105+ else put_c_above_o () )
106+ | `Bottom -> when_container_ready_and_in put_c_below_o
107+ | `Forced_bottom -> put_c_below_o () );
71108 (match side with
72109 | `Left ->
73- let right =
74- float_of_int Dom_html. document##.documentElement##.clientWidth
75- -. bb##.right
76- in
77- m##.style##.right := print_px right;
78- Manip.Class. add container " ot-tip-left"
110+ c_style##.right := print_px o_to_right;
111+ c_add_class " ot-tip-left"
79112 | `Right ->
80- let left = bb##.left in
81- m##.style##.left := print_px left;
82- Manip.Class. add container " ot-tip-right"
113+ c_style##.left := print_px o_left;
114+ c_add_class " ot-tip-right"
83115 | `Center ->
84- if right < left
116+ if o_to_right < o_left
85117 then (
86- let right =
87- float_of_int Dom_html. document##.documentElement##.clientWidth
88- -. ((bb##.right +. bb##.left) /. 2. )
89- in
90- m##.style##.right := print_px right;
91- Lwt. async @@ fun () ->
92- let % lwt () = Ot_nodeready. nodeready m in
93- let off = float (m##.offsetWidth / 2 ) in
94- if off < = right -. 1.
95- then (
96- m##.style##.right := print_px (right -. off);
97- Manip.Class. add container " ot-tip-center" )
98- else Manip.Class. add container " ot-tip-left" ;
99- Lwt. return_unit)
100- else
101- let left = (bb##.right +. bb##.left) /. 2. in
102- m##.style##.left := print_px left;
103- Lwt. async @@ fun () ->
104- let % lwt () = Ot_nodeready. nodeready m in
105- let off = float (m##.offsetWidth / 2 ) in
106- if off < = left -. 1.
107- then (
108- m##.style##.left := print_px (left -. off);
109- Manip.Class. add container " ot-tip-center" )
110- else Manip.Class. add container " ot-tip-right" ;
111- Lwt. return_unit);
118+ c_style##.right := print_px o_center_to_right;
119+ when_container_ready get_half_c_width (fun half_c_width ->
120+ if half_c_width < = o_center_to_right -. 1.
121+ then (
122+ c_style##.right := print_px (o_center_to_right -. half_c_width);
123+ c_add_class " ot-tip-center" )
124+ else c_add_class " ot-tip-left" ))
125+ else (
126+ c_style##.left := print_px o_center_to_left;
127+ when_container_ready get_half_c_width (fun half_c_width ->
128+ if half_c_width < = o_center_to_left -. 1.
129+ then (
130+ c_style##.left := print_px (o_center_to_left -. half_c_width);
131+ c_add_class " ot-tip-center" )
132+ else c_add_class " ot-tip-right" )));
112133 let filter =
113134 D. div ~a: (a_onclick (fun _ -> ! close () ) :: filter_a) [container]
114135 in
0 commit comments