|
1 | | -= How to bind a JS library for OCaml |
| 1 | += Binding a JS library |
2 | 2 |
|
3 | | -== Accessing a JS variable, ex: {{{document}}}: |
4 | | -Write in .ml: |
5 | | - |
6 | | -<<code language="ocaml"| |
7 | | -let v = (Js.Unsafe.js_expr "window")##.document |
8 | | ->> |
9 | | -Alternatively, the global object can be used. In the browser, it refers to {{{window}}}. |
10 | | -<<code language="ocaml"| |
11 | | -let v = Js.Unsafe.global##.document |
12 | | ->> |
13 | | - |
14 | | -and in .mli: |
15 | | - |
16 | | -<<code language="ocaml"| |
17 | | -val v : ... Js.t |
18 | | ->> |
19 | | - |
20 | | -Be careful the function <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.js_expr>> |
21 | | -and the value <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.global>> are not typed. |
22 | | -Verify the library documentation before writing the type. |
23 | | - |
24 | | -== Binding a JS function |
25 | | - |
26 | | -Example from the Js module: |
27 | | -<<code language="ocaml"| |
28 | | -let decodeURI (s : js_string t) : js_string t = |
29 | | - Js.Unsafe.fun_call (Js.Unsafe.js_expr "decodeURI") [|Js.Unsafe.inject s|] |
30 | | ->> |
31 | | - |
32 | | -Have a look at the <<a_api subproject="js_of_ocaml"|module Js_of_ocaml.Js.Unsafe>> module API. |
33 | | - |
34 | | -== Using a JS constructor, ex: {{{F}}}: |
35 | | -Write in .ml: |
36 | | - |
37 | | -<<code language="ocaml"| |
38 | | -let f = Js.Unsafe.global##._F |
39 | | ->> |
40 | | -and in .mli: |
41 | | - |
42 | | -<<code language="ocaml"| |
43 | | -val f : (... -> ... Js.t) Js.constr |
44 | | ->> |
45 | | - |
46 | | -and if you want to use JS overloading, do, for example: |
47 | | -<<code language="ocaml"| |
48 | | -val f_fromInt : (int -> ... Js.t) Js.constr |
49 | | -val f_fromString : (js_string t -> ... Js.t) Js.constr |
50 | | -val f_blah : (#Dom_html.element t -> js_string t -> ... Js.t) Js.constr |
51 | | ->> |
52 | | - |
53 | | -== Accessing or modifying a JS property to an element |
54 | | - |
55 | | -When a property is missing in the OCaml interface of an element (for example |
56 | | -it has been dynamically added by a library), you can access using unsafe |
57 | | -features: |
58 | | - |
59 | | -<<code language="ocaml"| |
60 | | -(Js.Unsafe.coerce elt)##.blah |
61 | | ->> |
62 | | - |
63 | | -If you want to add yourself a new property: |
64 | | -<<code language="ocaml"| |
65 | | -(Js.Unsafe.coerce elt)##.blah := v |
66 | | ->> |
67 | | - |
68 | | -Here, {{{v}}} may be a JS value or an OCaml value. |
69 | | - |
70 | | -If you want to do that in type safe manner, just define new types for the |
71 | | -extended elements, or wrap the unsafe functions inside a getter and setter. |
72 | | - |
73 | | -== Binding a JS object |
74 | | - |
75 | | -Write in .ml and in .mli: |
76 | | - |
77 | | -<<code language="ocaml"| |
78 | | -class type my_js_type = object |
79 | | - |
80 | | - (* read only property, read value with t##.prop1 *) |
81 | | - method prop1 : int readonly_prop |
82 | | -
|
83 | | - (* write only property, write value with t##.prop2 := float 3.14 *) |
84 | | - method prop2 : number t writeonly_prop |
85 | | -
|
86 | | - (* both read and write *) |
87 | | - method prop3 : int prop |
88 | | -
|
89 | | - (* method or property starting with a capital letter can be prepend |
90 | | - with an underscore. *) |
91 | | - method _Array : ... (* to access the JavaScript property or method Array *) |
92 | | -
|
93 | | - (* Define two methods with different types, that translate to |
94 | | - the same JavaScript method. *) |
95 | | - method my_fun_int : int -> unit meth |
96 | | - method my_fun_string : js_string t -> unit meth |
97 | | - (* Both will actually call the my_fun JavaScript method. *) |
98 | | -
|
99 | | - (* To call a javascript method starting with one underscore *) |
100 | | - method __hiddenfun : .. |
101 | | - method __hiddenfun_ : .. |
102 | | - method __hiddenfun_something : .. |
103 | | - (* This will call the _hiddenfun Javascript method *) |
104 | | -
|
105 | | - (* To call the javascript method '_' *) |
106 | | - method __ : .. |
107 | | -end |
108 | | ->> |
109 | | - |
110 | | -=== Example binding some constants: |
111 | | - |
112 | | -For example if the JS class is used to define three constants {{{thelib.Theclass.VALUEA}}}, {{{thelib.Theclass.VALUEB}}}, {{{thelib.Theclass.VALUEC}}}, |
113 | | - |
114 | | -Since OCaml doesn't allow method names to start with capitalized letters, we can add an {{{_}}} |
115 | | - |
116 | | -write in .ml and .mli: |
117 | | - |
118 | | -<<code language="ocaml"| |
119 | | -type thetype |
120 | | - |
121 | | -class type theclass = object |
122 | | - method _VALUEA : thetype readonly_prop |
123 | | - method _VALUEB : thetype readonly_prop |
124 | | - method _VALUEC : thetype readonly_prop |
125 | | -end |
126 | | ->> |
127 | | - |
128 | | -and in .ml: |
129 | | - |
130 | | -<<code language="ocaml"| |
131 | | -let theclass = (Js.Unsafe.js_expr "thelib")##._Theclass |
132 | | ->> |
133 | | - |
134 | | -and in .mli: |
135 | | - |
136 | | -<<code language="ocaml"| |
137 | | -val theclass : theclass t |
138 | | ->> |
139 | | - |
140 | | -== Constructing JS objects manually |
141 | | -If you want to construct a JS object manually |
142 | | -(without calling a function or a constructor), you can use |
143 | | -the <<a_manual chapter="Ppx"|Ppx>> syntax extension. |
144 | | - |
145 | | -For example: |
146 | | -<<code language="ocaml"| |
147 | | -let options = object%js |
148 | | - val x = 3 (* read-only prop *) |
149 | | - val mutable y = 4 (* read/write prop *) |
150 | | -end |
151 | | ->> |
152 | | - |
153 | | -You can also use the unsafe <<a_api subproject="js_of_ocaml"|val Js_of_ocaml.Js.Unsafe.obj>>. |
154 | | - |
155 | | -== Set/get variables |
156 | | - |
157 | | -You can access every variable through the global javascript object ({{{window}}}): |
158 | | - |
159 | | -If the variable {{{var}}} has type {{{t Js.t}}} |
160 | | - |
161 | | -<<code language="ocaml"| |
162 | | -let set (x:t Js.t) = Js.Unsafe.global##.var := x |
163 | | -let get x : t Js.t = Js.Unsafe.global##.var |
164 | | ->> |
165 | | - |
166 | | -== Object property with multiple types |
167 | | - |
168 | | -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: |
169 | | - |
170 | | -Suppose the object {{{obj}}} has a property {{{prop}}} which can be either a string or a Dom node: |
171 | | - |
172 | | -<<code language="ocaml"| |
173 | | - |
174 | | -type dom_or_string |
175 | | - |
176 | | -class type obj = object |
177 | | - method prop : dom_or_string Js.t prop |
178 | | -end |
179 | | - |
180 | | -let obj : obj Js.t = Js.Unsafe.js_expr "obj" |
181 | | - |
182 | | -let string_constr : Js.js_string Js.t Js.constr = Js.Unsafe.global##._String |
183 | | - |
184 | | -let cast_string (x:dom_or_string Js.t) : Js.js_string Js.t Js.opt = |
185 | | - if Js.instanceof x string_constr |
186 | | - then Js.some (Js.Unsafe.coerce x) |
187 | | - else Js.null |
188 | | - |
189 | | -let node_constr : Dom.node Js.t Js.constr = Js.Unsafe.global##._Node |
190 | | - |
191 | | -let cast_node (x:dom_or_string Js.t) : Dom.node Js.t Js.opt = |
192 | | - if Js.instanceof x node_constr |
193 | | - then Js.some (Js.Unsafe.coerce x) |
194 | | - else Js.null |
195 | | - |
196 | | ->> |
197 | | - |
198 | | -== Check availability of method |
199 | | - |
200 | | -It is frequent that some methods are not implemented in some browsers. |
201 | | - |
202 | | -To check the presence of method {{{met}}}: |
203 | | - |
204 | | -<<code language="ocaml"| |
205 | | -let check_met obj = Js.Optdef.test ((Js.Unsafe.coerce obj)##.met) |
206 | | ->> |
| 3 | +This page has been merged into <<a_manual chapter="javascript-interop"|JavaScript interop>>. |
0 commit comments