File: event_arrows.ml

package info (click to toggle)
js-of-ocaml 2.2-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 7,612 kB
  • ctags: 10,589
  • sloc: ml: 36,459; makefile: 665; lisp: 41; sh: 14; ruby: 4; perl: 4
file content (174 lines) | stat: -rw-r--r-- 6,868 bytes parent folder | download
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
(* Js_of_ocaml library
 * http://www.ocsigen.org/js_of_ocaml/
 * Copyright (C) 2010 Vincent Balat
 * Laboratoire PPS - CNRS Université Paris Diderot
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, with linking exception;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *)

(** Events with arrows. *)

let (>>=) = Lwt.bind
let (>|=) = Lwt.(>|=)

type canceller = (unit -> unit) option ref (* canceller function *)
type ('a, 'b) t = 'a -> canceller -> ('b * canceller) Lwt.t
let lwt_arr f = fun x c -> f x >>= fun r -> Lwt.return (r, c)
let arr f = fun x c -> Lwt.return (f x, c)
let (>>>) f g = fun x c -> f x c >>= fun (y, c) -> g y c
let (>>>|) f g = f >>> lwt_arr g
let run (a : ('a, 'b) t) x = let c = ref None in ignore (a x c); c

let set_canceller clr c = clr := Some c

let cancel c = match !c with
  | None -> ()
  | Some f -> f ()

let make_event eventkind
    ?(use_capture = false) ?(keep_default = false) ?(propagate = false)
    (target : #Dom_html.eventTarget Js.t) _ c =
  let el = ref Js.null in
  let t, w = Lwt.wait () in
  let cancel () = Js.Opt.iter !el Dom_html.removeEventListener in
  set_canceller c cancel;
  el := Js.some
    (Dom_html.addEventListener
       target eventkind
       (Dom_html.handler
          (fun (ev : #Dom_html.event Js.t) ->
            if not propagate
            then Dom_html.stopPropagation ev;
            cancel ();
            Lwt.wakeup w (ev, c);
            Js.bool keep_default))
       (Js.bool use_capture)
    );
  t

let rec loop_event f ?use_capture ?keep_default ?propagate target handler x c =
  (f ?use_capture ?keep_default ?propagate target >>> handler) () c
  >>= fun (y, c) ->
  loop_event f ?use_capture ?keep_default ?propagate target handler x c

(*  let rec loop f handler = f >>> handler >>> loop f handler *)

let make_state eventkind
    ?(use_capture = false) ?(keep_default = false) ?(propagate = false)
    (target : #Dom_html.eventTarget Js.t) handler _ c =
  let el = ref Js.null in
  let c1 = ref None in
  let cancel0 () = cancel c1; Js.Opt.iter !el Dom_html.removeEventListener in
  set_canceller c cancel0;
  let locked = ref false in
  let state = ref None in
  let rec f (ev : #Dom_html.event Js.t) =
    if !locked
    then state := Some ev (* We keep the more recent state during the handler *)
    else begin
      locked := true;
      ignore (handler ev c1 >|= fun r -> 
              locked := false;
              match !state with
                | None -> ()
                | Some ev -> state := None; f ev);
    end
  in
  el := Js.some
    (Dom_html.addEventListener
       target eventkind
       (Dom_html.handler (fun ev -> 
         if not propagate
         then Dom_html.stopPropagation ev;
         f ev;
         Js.bool keep_default))
       (Js.bool use_capture)
    );
  fst (Lwt.wait ())

let first l x c =
  let cancellers = ref [] in
  let cancel () = List.iter cancel !cancellers in
  set_canceller c cancel;
  let t, w = Lwt.wait () in
  let f x c0 =
    cancel ();
    Lwt.wakeup w (x, c);
    Lwt.return (x, c0)
  in
  cancellers := List.map (fun e -> run (e >>> f) x) l;
  t

let rec iter l x c =
  first l x c >>= fun (y, c) ->
  iter l x c


let click ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.click ?use_capture ?keep_default ?propagate t a c
let dblclick ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.dblclick ?use_capture ?keep_default ?propagate t a c
let mousedown ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mousedown ?use_capture ?keep_default ?propagate t a c
let mouseup ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mouseup ?use_capture ?keep_default ?propagate t a c
let mouseover ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mouseover ?use_capture ?keep_default ?propagate t a c
let mousemove ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mousemove ?use_capture ?keep_default ?propagate t a c
let mouseout ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mouseout ?use_capture ?keep_default ?propagate t a c

let keypress ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.keypress ?use_capture ?keep_default ?propagate t a c
let keydown ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.keydown ?use_capture ?keep_default ?propagate t a c
let keyup ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.keyup ?use_capture ?keep_default ?propagate t a c

(* TODO: implement with Dom_html.addMousewheelEventListener
let mousewheel ?use_capture ?keep_default ?propagate t a c =
  make_event Dom_html.Event.mousewheel ?use_capture ?keep_default ?propagate t a c
*)

let clicks ?use_capture ?keep_default ?propagate t =
  loop_event click ?use_capture ?keep_default ?propagate t
let dblclicks ?use_capture ?keep_default ?propagate t =
  loop_event dblclick ?use_capture ?keep_default ?propagate t
let mousedowns ?use_capture ?keep_default ?propagate t =
  make_state Dom_html.Event.mousedown ?use_capture ?keep_default ?propagate t
let mouseups ?use_capture ?keep_default ?propagate t =
  make_state Dom_html.Event.mouseup ?use_capture ?keep_default ?propagate t
let mouseovers ?use_capture ?keep_default ?propagate t =
  loop_event mouseover ?use_capture ?keep_default ?propagate t
let mousemoves ?use_capture ?keep_default ?propagate t =
  make_state Dom_html.Event.mousemove ?use_capture ?keep_default ?propagate t
let mouseouts ?use_capture ?keep_default ?propagate t =
  loop_event mouseout ?use_capture ?keep_default ?propagate t
(*VVV make_state? *)

let keypresses ?use_capture ?keep_default ?propagate t =
  loop_event keypress ?use_capture ?keep_default ?propagate t
let keydowns ?use_capture ?keep_default ?propagate t =
  make_state Dom_html.Event.keydown ?use_capture ?keep_default ?propagate t
let keyups ?use_capture ?keep_default ?propagate t =
  make_state Dom_html.Event.keyup ?use_capture ?keep_default ?propagate t

(* TODO: implement with Dom_html.addMousewheelEventListener
let mousewheels ?use_capture ?keep_default ?propagate t =
  loop_event mousewheel ?use_capture ?keep_default ?propagate t
*)