File: bindings.wiki

package info (click to toggle)
js-of-ocaml 5.9.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 32,020 kB
  • sloc: ml: 91,250; javascript: 57,289; ansic: 315; makefile: 271; lisp: 23; sh: 6; perl: 4
file content (206 lines) | stat: -rw-r--r-- 5,567 bytes parent folder | download | duplicates (2)
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
= How to bind a JS library for OCaml

==Accessing a JS variable, ex: {{{document}}}:
Write in .ml:

<<code language="ocaml"|
let v = (Js.Unsafe.js_expr "window")##.document
>>
Alternatively, the global object can be used. In the browser, it refers to {{{window}}}.
<<code language="ocaml"|
let v = Js.Unsafe.global##.document
>>

and in .mli:

<<code language="ocaml"|
val v : ... Js.t
>>

Be careful the function <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.js_expr>>
and the value <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.global>> are not typed.
Verify the library documentation before writing the type.

==Binding a JS function

Example from the Js module:
<<code language="ocaml"|
let decodeURI (s : js_string t) : js_string t =
  Js.Unsafe.fun_call (Js.Unsafe.js_expr "decodeURI") [|Js.Unsafe.inject s|]
>>

Have a look at the <<a_api subproject="js_of_ocaml"|module Js_of_ocaml.Js.Unsafe>> module API.

==Using a JS constructor, ex: {{{F}}}:
Write in .ml:

<<code language="ocaml"|
let f = Js.Unsafe.global##._F
>>
and in .mli:

<<code language="ocaml"|
val f : (... -> ... Js.t) Js.constr
>>

and if you want to use JS overloading, do, for example:
<<code language="ocaml"|
val f_fromInt : (int -> ... Js.t) Js.constr
val f_fromString : (js_string t -> ... Js.t) Js.constr
val f_blah : (#Dom_html.element t -> js_string t -> ... Js.t) Js.constr
>>

==Accessing or modifying a JS property to an element

When a property is missing in the OCaml interface of an element (for example
it has been dynamically added by a library), you can access using unsafe
features:

<<code language="ocaml"|
(Js.Unsafe.coerce elt)##.blah
>>

If you want to add yourself a new property:
<<code language="ocaml"|
(Js.Unsafe.coerce elt)##.blah := v
>>

Here, {{{v}}} may be a JS value or an OCaml value.

If you want to do that in type safe manner, just define new types for the
extended elements, or wrap the unsafe functions inside a getter and setter.

== Binding a JS object ==

Write in .ml and in .mli:

<<code language="ocaml"|
class type my_js_type = object

  (* read only property, read value with t##.prop1 *)
  method prop1 : int readonly_prop

  (* write only property, write value with t##.prop2 := 3.14 *)
  method prop2 : float writeonly_prop

  (* both read and write *)
  method prop3 : int prop

  (* method or property starting with a capital letter can be prepend
     with an underscore. *)
  method _Array : ... (* to access the JavasScript property or method Array *)

  (* Define two methods with different types, that translate to
     the same JavaScript method. *)
  method my_fun_int : int -> unit meth
  method my_fun_string : js_string t -> unit meth
  (* Both will actually call the my_fun JavaScript method. *)

  (* To call a javascript method starting with one underscore *)
  method __hiddenfun : ..
  method __hiddenfun_ : ..
  method __hiddenfun_something : ..
  (* This will call the _hiddenfun Javascript method *)

  (* To call the javascript method '_' *)
  method __ : ..
end
>>

===Example binding some constants:

For example if the JS class is used to define three constants {{{thelib.Theclass.VALUEA}}}, {{{thelib.Theclass.VALUEB}}}, {{{thelib.Theclass.VALUEC}}},

Since ocaml doesn't allows method name to start with capitalised letter, we can add an {{{_}}}

write in .ml and .mli:

<<code language="ocaml"|
type thetype

class type theclass = object
  method _VALUEA : thetype readonly_prop
  method _VALUEB : thetype readonly_prop
  method _VALUEC : thetype readonly_prop
end
>>

and in .ml:

<<code language="ocaml"|
let theclass = (Js.Unsafe.js_expr "thelib")##._Theclass
>>

and in .mli:

<<code language="ocaml"|
val theclass : theclass t
>>

==Constructing JS objects manually
If you want to construct a JS object manually
(without calling a function or a constructor), you can use
the <<a_manual chapter="Ppx"|Ppx>> syntax extension.

For example:
<<code language="ocaml"|
let options = object%js
  val x = 3 (* read-only prop *)
  val mutable y = 4 (* read/write prop *)
end
>>

You can also use the unsafe <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.obj>>.

== Set/get variables

You can access every variable through the global javascript object ({{{window}}}):

If the variable {{{var}}} has type {{{t Js.t}}}

<<code language="ocaml"|
let set (x:t Js.t) = Js.Unsafe.global##.var := x
let get x : t Js.t = Js.Unsafe.global##.var
>>

== Object property with multiple types

If you want to read a property of an object which can have multiple types, you can define an intermediate type to do typesafe casting ex:

Suppose the object {{{obj}}} has a property {{{prop}}} which can be either a string or a Dom node:

<<code language="ocaml"|

type dom_or_string

class type obj = object
  method prop : dom_or_string Js.t prop
end

let obj : obj Js.t = Js.Unsafe.js_expr "obj"

let string_constr : Js.js_string Js.t Js.constr = Js.Unsafe.global##._String

let cast_string (x:dom_or_string Js.t) : Js.js_string Js.t Js.opt =
  if Js.instanceof x string_constr
  then Js.some (Js.Unsafe.coerce x)
  else Js.null

let node_constr : Dom.node Js.t Js.constr = Js.Unsafe.global##._Node

let cast_node (x:dom_or_string Js.t) : Dom.node Js.t Js.opt =
  if Js.instanceof x node_constr
  then Js.some (Js.Unsafe.coerce x)
  else Js.null

>>

== Check availability of method

It is frequent that some method are not to be implemented in some browser.

To check the presence of method {{{met}}}:

<<code language="ocaml"|
let check_met obj = Js.Optdef.test ((Js.Unsafe.coerce obj)##.met)
>>