1// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
2//
3// Use MakeWrapper to expose methods to JavaScript. When passing values directly, the following type conversions are performed:
4//
5//  | Go type               | JavaScript type       | Conversions back to interface{} |
6//  | --------------------- | --------------------- | ------------------------------- |
7//  | bool                  | Boolean               | bool                            |
8//  | integers and floats   | Number                | float64                         |
9//  | string                | String                | string                          |
10//  | []int8                | Int8Array             | []int8                          |
11//  | []int16               | Int16Array            | []int16                         |
12//  | []int32, []int        | Int32Array            | []int                           |
13//  | []uint8               | Uint8Array            | []uint8                         |
14//  | []uint16              | Uint16Array           | []uint16                        |
15//  | []uint32, []uint      | Uint32Array           | []uint                          |
16//  | []float32             | Float32Array          | []float32                       |
17//  | []float64             | Float64Array          | []float64                       |
18//  | all other slices      | Array                 | []interface{}                   |
19//  | arrays                | see slice type        | see slice type                  |
20//  | functions             | Function              | func(...interface{}) *js.Object |
21//  | time.Time             | Date                  | time.Time                       |
22//  | -                     | instanceof Node       | *js.Object                      |
23//  | maps, structs         | instanceof Object     | map[string]interface{}          |
24//
25// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa.
26package js
27
28// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key.
29type Object struct{ object *Object }
30
31// Get returns the object's property with the given key.
32func (o *Object) Get(key string) *Object { return o.object.Get(key) }
33
34// Set assigns the value to the object's property with the given key.
35func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) }
36
37// Delete removes the object's property with the given key.
38func (o *Object) Delete(key string) { o.object.Delete(key) }
39
40// Length returns the object's "length" property, converted to int.
41func (o *Object) Length() int { return o.object.Length() }
42
43// Index returns the i'th element of an array.
44func (o *Object) Index(i int) *Object { return o.object.Index(i) }
45
46// SetIndex sets the i'th element of an array.
47func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) }
48
49// Call calls the object's method with the given name.
50func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) }
51
52// Invoke calls the object itself. This will fail if it is not a function.
53func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) }
54
55// New creates a new instance of this type object. This will fail if it not a function (constructor).
56func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) }
57
58// Bool returns the object converted to bool according to JavaScript type conversions.
59func (o *Object) Bool() bool { return o.object.Bool() }
60
61// String returns the object converted to string according to JavaScript type conversions.
62func (o *Object) String() string { return o.object.String() }
63
64// Int returns the object converted to int according to JavaScript type conversions (parseInt).
65func (o *Object) Int() int { return o.object.Int() }
66
67// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
68func (o *Object) Int64() int64 { return o.object.Int64() }
69
70// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
71func (o *Object) Uint64() uint64 { return o.object.Uint64() }
72
73// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
74func (o *Object) Float() float64 { return o.object.Float() }
75
76// Interface returns the object converted to interface{}. See table in package comment for details.
77func (o *Object) Interface() interface{} { return o.object.Interface() }
78
79// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
80func (o *Object) Unsafe() uintptr { return o.object.Unsafe() }
81
82// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object.
83type Error struct {
84	*Object
85}
86
87// Error returns the message of the encapsulated JavaScript error object.
88func (err *Error) Error() string {
89	return "JavaScript error: " + err.Get("message").String()
90}
91
92// Stack returns the stack property of the encapsulated JavaScript error object.
93func (err *Error) Stack() string {
94	return err.Get("stack").String()
95}
96
97// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js).
98var Global *Object
99
100// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
101var Module *Object
102
103// Undefined gives the JavaScript value "undefined".
104var Undefined *Object
105
106// Debugger gets compiled to JavaScript's "debugger;" statement.
107func Debugger() {}
108
109// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
110func InternalObject(i interface{}) *Object {
111	return nil
112}
113
114// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords.
115func MakeFunc(fn func(this *Object, arguments []*Object) interface{}) *Object {
116	return Global.Call("$makeFunc", InternalObject(fn))
117}
118
119// Keys returns the keys of the given JavaScript object.
120func Keys(o *Object) []string {
121	if o == nil || o == Undefined {
122		return nil
123	}
124	a := Global.Get("Object").Call("keys", o)
125	s := make([]string, a.Length())
126	for i := 0; i < a.Length(); i++ {
127		s[i] = a.Index(i).String()
128	}
129	return s
130}
131
132// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript.
133func MakeWrapper(i interface{}) *Object {
134	v := InternalObject(i)
135	o := Global.Get("Object").New()
136	o.Set("__internal_object__", v)
137	methods := v.Get("constructor").Get("methods")
138	for i := 0; i < methods.Length(); i++ {
139		m := methods.Index(i)
140		if m.Get("pkg").String() != "" { // not exported
141			continue
142		}
143		o.Set(m.Get("name").String(), func(args ...*Object) *Object {
144			return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args)
145		})
146	}
147	return o
148}
149
150// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice.
151func NewArrayBuffer(b []byte) *Object {
152	slice := InternalObject(b)
153	offset := slice.Get("$offset").Int()
154	length := slice.Get("$length").Int()
155	return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length)
156}
157
158// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
159type M map[string]interface{}
160
161// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
162type S []interface{}
163
164func init() {
165	// avoid dead code elimination
166	e := Error{}
167	_ = e
168}
169