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)
>>
|