├── .gitignore ├── README.md ├── background └── background.go ├── backgroundexec └── backgroundexec.go ├── barcodescanner └── barcodescanner.go ├── ble ├── ble.go └── peripheral.go ├── chrome └── tcpsockets │ └── tcpsockets.go ├── device └── device.go ├── diagnostic ├── diagnostic.go └── location │ └── location.go ├── dialogs └── dialogs.go ├── file └── file.go ├── geolocation └── geolocation.go ├── globalization └── globalization.go ├── goco.go ├── hotcode └── hotcode.go ├── motion └── motion.go ├── mqtt └── mqtt.go ├── nativestorage └── nativestorage.go ├── netinfo └── netinfo.go ├── nfc └── nfc.go ├── notifications └── notifications.go ├── orientation └── orientation.go ├── push └── push.go ├── smsreceive └── smsreceive.go ├── univlinks └── univlinks.go └── vibration └── vibration.go /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # goco 2 | Cordova bindings for GopherJS 3 | 4 | [![GoDoc](https://godoc.org/github.com/jaracil/goco?status.png)](https://godoc.org/github.com/jaracil/goco) 5 | 6 | Download: 7 | ```shell 8 | go get github.com/jaracil/goco 9 | ``` 10 | -------------------------------------------------------------------------------- /background/background.go: -------------------------------------------------------------------------------- 1 | // Package background is a GopherJS wrapper for cordova background-mode plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-background-mode 5 | package background 6 | 7 | import ( 8 | "github.com/gopherjs/gopherjs/js" 9 | ) 10 | 11 | var instance *js.Object 12 | 13 | func mo() *js.Object { 14 | if instance == nil { 15 | instance = js.Global.Get("cordova").Get("plugins").Get("backgroundMode") 16 | } 17 | return instance 18 | } 19 | 20 | // Enable enables/disables background mode. 21 | func Enable(en bool) { 22 | mo().Call("setEnabled", en) 23 | } 24 | 25 | // InBackground returns true if app is in background 26 | func InBackground() bool { 27 | return mo().Call("isActive").Bool() 28 | } 29 | 30 | // MoveToBackground moves the app to background. (Android only) 31 | func MoveToBackground() { 32 | mo().Call("moveToBackground") 33 | } 34 | 35 | // MoveToForeground moves the app to foreground. (Android only) 36 | func MoveToForeground() { 37 | mo().Call("moveToForeground") 38 | } 39 | 40 | // OverrideBackButton change backbutton behavior. When back button is pressed 41 | // the app is moved to background instead of close it. 42 | func OverrideBackButton() { 43 | mo().Call("overrideBackButton") 44 | } 45 | 46 | // ExcludeFromTaskList exclude the app from the recent task list works on Android 5.0+. 47 | func ExcludeFromTaskList() { 48 | mo().Call("ExcludeFromTaskList") 49 | } 50 | 51 | // IsScreenOff returns false when screen is off. 52 | func IsScreenOff() (ret bool) { 53 | ch := make(chan struct{}) 54 | success := func(b bool) { 55 | ret = !b 56 | close(ch) 57 | } 58 | mo().Call("isScreenOff", success) 59 | <-ch 60 | return 61 | } 62 | 63 | // Wakeup turns on the screen. 64 | func Wakeup() { 65 | mo().Call("wakeup") 66 | } 67 | 68 | // Unlock moves the app to foreground even the device is locked. 69 | func Unlock() { 70 | mo().Call("unlock") 71 | } 72 | 73 | // DisableWebViewOptimizations disable web view optimizations. 74 | // Various APIs like playing media or tracking GPS position in background 75 | // might not work while in background even the background mode is active. 76 | // To fix such issues the plugin provides a method to disable most optimizations done by Android/CrossWalk. 77 | func DisableWebViewOptimizations() { 78 | mo().Call("disableWebViewOptimizations") 79 | } 80 | 81 | // OnEnable sets the function to be called when background mode is enabled. 82 | func OnEnable(f func()) { 83 | mo().Call("on", "enable", f) 84 | } 85 | 86 | // OnDisable sets the function to be called when background mode is disabled. 87 | func OnDisable(f func()) { 88 | mo().Call("on", "disable", f) 89 | } 90 | 91 | // OnActivate sets the function to be called when app enters in background. 92 | func OnActivate(f func()) { 93 | mo().Call("on", "activate", f) 94 | } 95 | 96 | // OnDeactivate sets the function to be called when app enters in foreground. 97 | func OnDeactivate(f func()) { 98 | mo().Call("on", "deactivate", f) 99 | } 100 | 101 | // OnFailure sets the function to be called on failure 102 | func OnFailure(f func()) { 103 | mo().Call("on", "failure", f) 104 | } 105 | 106 | // UnEnable removes OnEnable callback function 107 | func UnEnable(f func()) { 108 | mo().Call("un", "enable", f) 109 | } 110 | 111 | // UnDisable removes OnDisable callback function 112 | func UnDisable(f func()) { 113 | mo().Call("un", "disable", f) 114 | } 115 | 116 | // UnActivate removes OnActivate callback function 117 | func UnActivate(f func()) { 118 | mo().Call("un", "activate", f) 119 | } 120 | 121 | // UnDeactivate removes OnDeactivate callback function 122 | func UnDeactivate(f func()) { 123 | mo().Call("un", "deactivate", f) 124 | } 125 | 126 | // UnFailure removes OnFailure callback function 127 | func UnFailure(f func()) { 128 | mo().Call("un", "failure", f) 129 | } 130 | 131 | // SetDefaults sets notification defaults to indicate that the app is executing tasks in background and being paused would disrupt the user, 132 | // the plug-in has to create a notification while in background - like a download progress bar. 133 | // 134 | // See cordova module documentation for more information. 135 | func SetDefaults(opts interface{}) { 136 | mo().Call("setDefaults", opts) 137 | } 138 | 139 | // Configure modifies the currently displayed notification 140 | func Configure(opts interface{}) { 141 | mo().Call("configure", opts) 142 | } 143 | -------------------------------------------------------------------------------- /backgroundexec/backgroundexec.go: -------------------------------------------------------------------------------- 1 | // Package backgroundexec is a GopherJS wrapper for allowing execution on iOS when app goes to background (https://github.com/jocull/phonegap-backgroundjs). 2 | // 3 | // Install plugin: 4 | // cordova plugin add https://github.com/jocull/phonegap-backgroundjs 5 | package backgroundexec 6 | 7 | import ( 8 | "github.com/gopherjs/gopherjs/js" 9 | ) 10 | 11 | // SetBackgroundSeconds allows background execution for seconds 12 | func SetBackgroundSeconds(seconds int) { 13 | rootObj().Call("setBackgroundSeconds", seconds) 14 | } 15 | 16 | // LockBackgroundTime allows background execution until max allowed time (180s) 17 | func LockBackgroundTime() { 18 | rootObj().Call("lockBackgroundTime") 19 | } 20 | 21 | // UnlockBackgroundTime stops background tasks immediately 22 | func UnlockBackgroundTime() { 23 | rootObj().Call("unlockBackgroundTime") 24 | } 25 | 26 | func rootObj() *js.Object { 27 | return js.Global.Get("plugins").Get("backgroundjs") 28 | } 29 | -------------------------------------------------------------------------------- /barcodescanner/barcodescanner.go: -------------------------------------------------------------------------------- 1 | // Package barcodescanner is a GopherJS wrapper for barcodescanner plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-barcodescanner 5 | // phonegap plugin add phonegap-plugin-barcodescanner 6 | // 7 | // (Incomplete implementation, missing "Encode" function) 8 | package barcodescanner 9 | 10 | import ( 11 | "github.com/gopherjs/gopherjs/js" 12 | "errors" 13 | "strings" 14 | ) 15 | 16 | var ( 17 | ErrCanceled = errors.New("BarcodeScanner error: User has canceled the scanner") 18 | ErrUnexpectedError = errors.New("BarcodeScanner error: Unexpected error") 19 | ErrPluginNotAvailable = errors.New("BarcodeScanner error: BarcodeScanner not found") 20 | ) 21 | 22 | type Format string 23 | 24 | const ( 25 | QR_CODE Format = "QR_CODE" 26 | DATA_MATRIX Format = "DATA_MATRIX" 27 | UPC_A Format = "UPC_A" 28 | UPC_E Format = "UPC_E" 29 | EAN_8 Format = "EAN_8" 30 | EAN_13 Format = "EAN_13" 31 | CODE_39 Format = "CODE_39" 32 | CODE_93 Format = "CODE_93" 33 | CODE_128 Format = "CODE_128" 34 | CODABAR Format = "CODABAR" 35 | ITF Format = "ITF" 36 | RSS_14 Format = "RSS14" 37 | PDF_417 Format = "PDF417" 38 | RSS_EXPANDED Format = "RSS_EXPANDED" 39 | MSI Format = "MSI" 40 | AZTEC Format = "AZTEC" 41 | ) 42 | 43 | type Orientation string 44 | 45 | const ( 46 | Landscape Orientation = "landscape" 47 | Portrait Orientation = "portrait" 48 | Both Orientation = "" 49 | ) 50 | 51 | type Scanner struct { 52 | *js.Object 53 | PreferFrontCamera bool `js:"preferFrontCamera"` // iOS/Android 54 | ShowFlipCameraButton bool `js:"showFlipCameraButton"` // iOS/Android 55 | ShowTorchButton bool `js:"showTorchButton"` // iOS/Android 56 | TorchOn bool `js:"torchOn"` // Android 57 | SaveHistory bool `js:"saveHistory"` // Android 58 | Prompt string `js:"prompt"` // Android 59 | ResultDisplayDuration int `js:"resultDisplayDuration"` // Android 60 | Formats Format `js:"formats"` // See https://www.npmjs.com/package/cordova-plugin-barcodescanner 61 | Orientation Orientation `js:"orientation"` // Android 62 | DisableAnimations bool `js:"disableAnimations"` // iOS 63 | DisableSuccessBeep bool `js:"disableSuccessBeep"` 64 | } 65 | 66 | type Response struct { 67 | *js.Object 68 | Text string `js:"text"` 69 | Format Format `js:"format"` 70 | } 71 | 72 | var instance *js.Object 73 | 74 | func mo() *js.Object { 75 | if instance == nil { 76 | instance = js.Global.Get("cordova").Get("plugins").Get("barcodeScanner") 77 | } 78 | return instance 79 | } 80 | 81 | // NewScanner returns new Scanner object with default values 82 | func NewScanner() *Scanner { 83 | cfg := &Scanner{Object: js.Global.Get("Object").New()} 84 | cfg.SetFormats(QR_CODE) 85 | 86 | return cfg 87 | } 88 | 89 | // SetFormats defines which format should be decode, it can be multiple formats like `SetFormats(QR_CODE, EAN_13)`. 90 | func (cfg *Scanner) SetFormats(format ...Format) { 91 | var str strings.Builder 92 | 93 | for _, f := range format { 94 | str.WriteString(",") 95 | str.WriteString(string(f)) 96 | } 97 | 98 | cfg.Formats = Format(str.String()[1:]) 99 | } 100 | 101 | // Scan initialize the scanner, allowing the user to scan the barcode using the camera. It will return a non-nil error 102 | // when is impossible the use the plugin or use the camera or impossible to decode the barcode, if the user cancel the 103 | // scanner a non-nil error are also given. 104 | func (cfg *Scanner) Scan() (resp *Response, err error) { 105 | if mo() == js.Undefined || mo() == nil { 106 | return resp, ErrPluginNotAvailable 107 | } 108 | 109 | ch := make(chan struct{}) 110 | success := func(obj *js.Object) { 111 | resp = &Response{Object: obj} 112 | 113 | if obj.Get("cancelled").Bool() { 114 | err = ErrCanceled 115 | } 116 | 117 | close(ch) 118 | } 119 | fail := func(obj *js.Object) { 120 | err = ErrUnexpectedError 121 | close(ch) 122 | } 123 | mo().Call("scan", success, fail, cfg) 124 | <-ch 125 | return 126 | } 127 | -------------------------------------------------------------------------------- /ble/ble.go: -------------------------------------------------------------------------------- 1 | package ble 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "github.com/gopherjs/gopherjs/js" 8 | ) 9 | 10 | var ( 11 | // Status flags 12 | wantScan = false 13 | scaning = false 14 | paused = 0 15 | 16 | // Scan Params 17 | scanSrv []string 18 | scanCbFun func(*Peripheral) 19 | scanDups bool 20 | ) 21 | 22 | var instance *js.Object 23 | 24 | func mo() *js.Object { 25 | if instance == nil { 26 | instance = js.Global.Get("ble") 27 | } 28 | return instance 29 | } 30 | 31 | func stringify(obj *js.Object) string { 32 | return js.Global.Get("JSON").Call("stringify", obj).String() 33 | } 34 | 35 | func PauseScan() { 36 | paused++ 37 | stopScan() 38 | } 39 | 40 | func ResumeScan() { 41 | if paused > 0 { 42 | paused-- 43 | } 44 | if wantScan && paused == 0 { 45 | startScan(scanSrv, scanCbFun, scanDups) 46 | } 47 | } 48 | 49 | func Scaning() bool { 50 | return scaning 51 | } 52 | 53 | func startScan(srv []string, cbFun func(*Peripheral), dups bool) { 54 | if scaning || !wantScan { 55 | return 56 | } 57 | scaning = true 58 | options := map[string]interface{}{"reportDuplicates": dups} 59 | mo().Call("startScanWithOptions", srv, options, func(obj *js.Object) { 60 | p := newPeripheral(obj) 61 | cbFun(p) 62 | }) 63 | } 64 | 65 | func StartScan(srv []string, cbFun func(*Peripheral), dups bool) { 66 | scanSrv = srv 67 | scanCbFun = cbFun 68 | scanDups = dups 69 | wantScan = true 70 | if paused == 0 { 71 | startScan(scanSrv, scanCbFun, scanDups) 72 | } 73 | 74 | } 75 | 76 | func stopScan() (err error) { 77 | if !scaning { 78 | return 79 | } 80 | scaning = false 81 | ch := make(chan struct{}) 82 | success := func() { 83 | close(ch) 84 | } 85 | failure := func(obj *js.Object) { 86 | err = errors.New("Error closing BLE scan <" + stringify(obj) + ">") 87 | close(ch) 88 | } 89 | mo().Call("stopScan", success, failure) 90 | <-ch 91 | return 92 | } 93 | 94 | func StopScan() (err error) { 95 | wantScan = false 96 | return stopScan() 97 | } 98 | 99 | func Connect(id string, endConnCb func(per *Peripheral)) (per *Peripheral, err error) { 100 | if !IsEnabled() { 101 | return nil, errors.New("Bluetooth disabled") 102 | } 103 | ch := make(chan struct{}) 104 | connected := false 105 | success := func(obj *js.Object) { 106 | per = newPeripheral(obj) 107 | connected = true 108 | close(ch) 109 | } 110 | failure := func(obj *js.Object) { 111 | if connected { 112 | if endConnCb != nil { 113 | endConnCb(per) 114 | } 115 | } else { 116 | err = errors.New("Error connecting to BLE peripheral") 117 | close(ch) 118 | } 119 | } 120 | PauseScan() 121 | mo().Call("connect", id, success, failure) 122 | <-ch 123 | ResumeScan() 124 | return 125 | } 126 | 127 | func Disconnect(id string) (err error) { 128 | ch := make(chan struct{}) 129 | success := func() { 130 | close(ch) 131 | } 132 | failure := func(obj *js.Object) { 133 | err = errors.New("Error closing BLE peripheral: <" + stringify(obj) + ">") 134 | close(ch) 135 | } 136 | mo().Call("disconnect", id, success, failure) 137 | <-ch 138 | return 139 | } 140 | 141 | func IsConnected(id string) (ret bool) { 142 | ch := make(chan struct{}) 143 | success := func() { 144 | ret = true 145 | close(ch) 146 | } 147 | failure := func() { 148 | ret = false 149 | close(ch) 150 | } 151 | mo().Call("isConnected", id, success, failure) 152 | <-ch 153 | return 154 | } 155 | 156 | func Read(id, srv, char string) (ret []byte, err error) { 157 | ch := make(chan struct{}) 158 | success := func(obj *js.Object) { 159 | ret = js.Global.Get("Uint8Array").New(obj).Interface().([]byte) 160 | close(ch) 161 | } 162 | failure := func(obj *js.Object) { 163 | err = errors.New("BLE read error: <" + stringify(obj) + ">") 164 | close(ch) 165 | } 166 | mo().Call("read", id, srv, char, success, failure) 167 | <-ch 168 | return 169 | } 170 | 171 | func Write(id, srv, char string, data []byte) (err error) { 172 | ch := make(chan struct{}) 173 | success := func() { 174 | close(ch) 175 | } 176 | failure := func(obj *js.Object) { 177 | err = errors.New("BLE write error: <" + stringify(obj) + ">") 178 | close(ch) 179 | } 180 | arr := js.NewArrayBuffer(data) 181 | mo().Call("write", id, srv, char, arr, success, failure) 182 | <-ch 183 | return 184 | } 185 | 186 | func WriteWithoutResponse(id, srv, char string, data []byte) (err error) { 187 | ch := make(chan struct{}) 188 | success := func() { 189 | close(ch) 190 | } 191 | failure := func(obj *js.Object) { 192 | err = errors.New("BLE write error: <" + stringify(obj) + ">") 193 | close(ch) 194 | } 195 | arr := js.NewArrayBuffer(data) 196 | mo().Call("writeWithoutResponse", id, srv, char, arr, success, failure) 197 | <-ch 198 | return 199 | } 200 | 201 | func StartNotification(id, srv, char string, recvCb func([]byte)) (err error) { 202 | success := func(obj *js.Object) { 203 | if recvCb != nil { 204 | recvCb(js.Global.Get("Uint8Array").New(obj).Interface().([]byte)) 205 | } 206 | } 207 | failure := func(obj *js.Object) { 208 | err = errors.New("BLE start notifications error: <" + stringify(obj) + ">") 209 | } 210 | mo().Call("startNotification", id, srv, char, success, failure) 211 | time.Sleep(10 * time.Millisecond) // Dirty Hack: Wait for eventual failure callback 212 | return 213 | } 214 | 215 | func StopNotification(id, srv, char string) (err error) { 216 | ch := make(chan struct{}) 217 | success := func() { 218 | close(ch) 219 | } 220 | failure := func(obj *js.Object) { 221 | err = errors.New("BLE stop notifications error: <" + stringify(obj) + ">") 222 | close(ch) 223 | } 224 | mo().Call("stopNotification", id, srv, char, success, failure) 225 | <-ch 226 | return 227 | } 228 | 229 | func IsEnabled() (ret bool) { 230 | ch := make(chan struct{}) 231 | success := func() { 232 | ret = true 233 | close(ch) 234 | } 235 | failure := func() { 236 | ret = false 237 | close(ch) 238 | } 239 | mo().Call("isEnabled", success, failure) 240 | <-ch 241 | return 242 | } 243 | 244 | func Enable() (err error) { 245 | ch := make(chan struct{}) 246 | success := func() { 247 | close(ch) 248 | } 249 | failure := func(obj *js.Object) { 250 | err = errors.New("Can't enable bluetooth: <" + stringify(obj) + ">") 251 | close(ch) 252 | } 253 | mo().Call("enable", success, failure) 254 | <-ch 255 | return 256 | } 257 | 258 | func StartStateNotifications(recvCb func(string)) (err error) { 259 | mo().Call("startStateNotifications", recvCb) 260 | return 261 | } 262 | 263 | func StopStateNotifications() (err error) { 264 | ch := make(chan struct{}) 265 | success := func() { 266 | close(ch) 267 | } 268 | failure := func(obj *js.Object) { 269 | err = errors.New("Can't stop bluetooth state notifications: <" + stringify(obj) + ">") 270 | close(ch) 271 | } 272 | mo().Call("stopStateNotifications", success, failure) 273 | <-ch 274 | return 275 | } 276 | 277 | func ShowBluetoothSettings() (err error) { 278 | ch := make(chan struct{}) 279 | success := func() { 280 | close(ch) 281 | } 282 | failure := func(obj *js.Object) { 283 | err = errors.New("Can't show bluetooth settings: <" + stringify(obj) + ">") 284 | close(ch) 285 | } 286 | mo().Call("showBluetoothSettings", success, failure) 287 | <-ch 288 | return 289 | } 290 | 291 | func ReadRSSI(id string) (val int, err error) { 292 | ch := make(chan struct{}) 293 | success := func(n int) { 294 | val = n 295 | close(ch) 296 | } 297 | failure := func(obj *js.Object) { 298 | err = errors.New("Can't get device RSSI: <" + stringify(obj) + ">") 299 | close(ch) 300 | } 301 | mo().Call("readRSSI", id, success, failure) 302 | <-ch 303 | return 304 | } 305 | -------------------------------------------------------------------------------- /ble/peripheral.go: -------------------------------------------------------------------------------- 1 | package ble 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/gopherjs/gopherjs/js" 9 | "github.com/jaracil/goco/device" 10 | ) 11 | 12 | type Characteristic struct { 13 | Service string 14 | Characteristic string 15 | Properties []string 16 | Descriptors []map[string]interface{} 17 | } 18 | 19 | type Peripheral struct { 20 | *js.Object 21 | name string 22 | txPowerLevel int 23 | flags int 24 | services []string 25 | servicesData map[string][]byte 26 | manufacturerData map[string][]byte 27 | unknown map[int][]byte 28 | characteristics []Characteristic 29 | } 30 | 31 | func newPeripheral(jsObj *js.Object) *Peripheral { 32 | per := &Peripheral{ 33 | Object: jsObj, 34 | services: []string{}, 35 | servicesData: map[string][]byte{}, 36 | manufacturerData: map[string][]byte{}, 37 | unknown: map[int][]byte{}, 38 | characteristics: []Characteristic{}, 39 | } 40 | per.parseAdvertising() 41 | per.extractCharacteristics() 42 | return per 43 | } 44 | 45 | func (p *Peripheral) Name() string { 46 | return p.Get("name").String() 47 | } 48 | 49 | func (p *Peripheral) ID() string { 50 | return p.Get("id").String() 51 | } 52 | 53 | func (p *Peripheral) RSSI() int { 54 | return p.Get("rssi").Int() 55 | } 56 | 57 | func (p *Peripheral) rawAdvData() []byte { 58 | return js.Global.Get("Uint8Array").New(p.Get("advertising")).Interface().([]byte) 59 | } 60 | 61 | func (p *Peripheral) Characteristics() []Characteristic { 62 | return p.characteristics 63 | } 64 | 65 | func (p *Peripheral) Services() (ret []string) { 66 | return p.services 67 | } 68 | 69 | func (p *Peripheral) ServiceData(key string) []byte { 70 | return p.servicesData[key] 71 | } 72 | 73 | func (p *Peripheral) Flags() int { 74 | return p.flags 75 | } 76 | 77 | func (p *Peripheral) TxPowerLevel() int { 78 | return p.txPowerLevel 79 | } 80 | 81 | func (p *Peripheral) ManufacturerData() map[string][]byte { 82 | return p.manufacturerData 83 | } 84 | 85 | func (p *Peripheral) Unknown() map[int][]byte { 86 | return p.unknown 87 | } 88 | 89 | func (p *Peripheral) extractCharacteristics() { 90 | if p.Get("characteristics") == js.Undefined { 91 | return 92 | } 93 | 94 | for _, item := range p.Get("characteristics").Interface().([]interface{}) { 95 | jsChar := item.(map[string]interface{}) 96 | char := Characteristic{ 97 | Characteristic: jsChar["characteristic"].(string), 98 | Service: jsChar["service"].(string), 99 | Properties: []string{}, 100 | Descriptors: []map[string]interface{}{}, 101 | } 102 | 103 | if jsChar["properties"] != nil { 104 | for _, prop := range jsChar["properties"].([]interface{}) { 105 | char.Properties = append(char.Properties, prop.(string)) 106 | } 107 | } 108 | 109 | if jsChar["descriptors"] != nil { 110 | for _, desc := range jsChar["descriptors"].([]interface{}) { 111 | char.Descriptors = append(char.Descriptors, desc.(map[string]interface{})) 112 | } 113 | } 114 | 115 | p.characteristics = append(p.characteristics, char) 116 | } 117 | } 118 | 119 | func (p *Peripheral) parseAdvertising() { 120 | if device.DevInfo.Platform == "Android" { 121 | p.parseAndroid() 122 | } else { 123 | p.parseIOS() 124 | } 125 | } 126 | 127 | func (p *Peripheral) parseIOS() { 128 | advertising := p.Get("advertising") 129 | 130 | rawName := advertising.Get("kCBAdvDataLocalName") 131 | if rawName != js.Undefined { 132 | p.name = rawName.String() 133 | } 134 | 135 | rawPowerLevel := advertising.Get("kCBAdvDataTxPowerLevel") 136 | if rawPowerLevel != js.Undefined { 137 | p.txPowerLevel = rawPowerLevel.Int() 138 | } 139 | 140 | rawServices := advertising.Get("kCBAdvDataServiceUUIDs") 141 | if rawServices != js.Undefined { 142 | for _, item := range rawServices.Interface().([]interface{}) { 143 | p.services = append(p.services, strings.ToLower(item.(string))) 144 | } 145 | } 146 | 147 | rawServicesData := advertising.Get("kCBAdvDataServiceData") 148 | if rawServicesData != js.Undefined { 149 | for _, key := range js.Keys(rawServicesData) { 150 | buffer := rawServicesData.Get(key) 151 | data := js.Global.Get("Uint8Array").New(buffer).Interface().([]byte) 152 | p.servicesData[strings.ToLower(key)] = data 153 | } 154 | } 155 | 156 | rawManufacturerData := advertising.Get("kCBAdvDataManufacturerData") 157 | if rawManufacturerData != js.Undefined { 158 | data := js.Global.Get("Uint8Array").New(rawManufacturerData).Interface().([]byte) 159 | if len(data) >= 2 { 160 | key := p.formatUUID(reverse(data[0:2])) 161 | value := data[2:] 162 | p.manufacturerData[strings.ToLower(key)] = value 163 | } 164 | } 165 | } 166 | 167 | func (p *Peripheral) parseAndroid() { 168 | arr := p.rawAdvData() 169 | i := 0 170 | 171 | for i < len(arr) { 172 | fieldLength := int(arr[i]) - 1 173 | i++ 174 | 175 | if fieldLength == -1 { 176 | break 177 | } 178 | 179 | fieldType := arr[i] 180 | i++ 181 | 182 | switch fieldType { 183 | case 0x01: 184 | p.flags = int(arr[i]) 185 | i += int(fieldLength) 186 | case 0x02: 187 | fallthrough 188 | case 0x03: 189 | i = p.extractUUIDs(arr, i, fieldLength, 2) 190 | case 0x04: 191 | fallthrough 192 | case 0x05: 193 | i = p.extractUUIDs(arr, i, fieldLength, 4) 194 | case 0x06: 195 | fallthrough 196 | case 0x07: 197 | i = p.extractUUIDs(arr, i, fieldLength, 16) 198 | case 0x08: 199 | fallthrough 200 | case 0x09: 201 | fieldData := arr[i : i+fieldLength] 202 | p.name = string(fieldData) 203 | i += fieldLength 204 | case 0x0a: 205 | p.txPowerLevel = int(arr[i]) 206 | i += fieldLength 207 | case 0x16: 208 | key := p.formatUUID(arr[i : i+2]) 209 | value := arr[i+2 : i+2+fieldLength-2] 210 | p.servicesData[key] = value 211 | i += fieldLength 212 | case 0xff: 213 | key := p.formatUUID(reverse(arr[i : i+2])) 214 | value := arr[i+2 : i+2+fieldLength-2] 215 | p.manufacturerData[key] = value 216 | i += fieldLength 217 | default: 218 | p.unknown[int(fieldType)] = arr[i : i+fieldLength] 219 | i += fieldLength 220 | } 221 | } 222 | } 223 | 224 | func (p *Peripheral) extractUUIDs(advertising []byte, index int, length int, uuidNumBytes int) int { 225 | uuids := []string{} 226 | remaining := length 227 | i := index 228 | 229 | for remaining > 0 { 230 | uuids = append(uuids, p.formatUUID(reverse(advertising[i:i+uuidNumBytes]))) 231 | i += uuidNumBytes 232 | remaining -= uuidNumBytes 233 | } 234 | 235 | p.services = append(p.services, uuids...) 236 | 237 | return i 238 | } 239 | 240 | func (p *Peripheral) formatUUID(data []byte) string { 241 | result := "" 242 | 243 | for _, val := range data { 244 | result += fmt.Sprintf("%02x", val) 245 | } 246 | 247 | if len(result) == 32 { 248 | result = result[0:8] + "-" + result[8:12] + "-" + result[12:16] + "-" + result[16:20] + "-" + result[20:] 249 | } 250 | 251 | return result 252 | } 253 | 254 | func toUUID(data []byte) (ret string) { 255 | if data != nil && len(data) == 16 { 256 | ret = hex.EncodeToString(data[0:4]) + "-" + hex.EncodeToString(data[4:6]) + "-" + hex.EncodeToString(data[6:8]) + "-" + hex.EncodeToString(data[8:10]) + "-" + hex.EncodeToString(data[10:16]) 257 | } 258 | return 259 | } 260 | 261 | func reverse(data []byte) []byte { 262 | if data != nil { 263 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 264 | data[i], data[j] = data[j], data[i] 265 | } 266 | } 267 | return data 268 | } 269 | -------------------------------------------------------------------------------- /chrome/tcpsockets/tcpsockets.go: -------------------------------------------------------------------------------- 1 | // Package tcpsockets is a GopherJS wrapper for chrome.sockets.tcp plugin 2 | // https://www.npmjs.com/package/cordova-plugin-chrome-apps-sockets-tcp 3 | // https://developer.chrome.com/apps/sockets_tcp 4 | // 5 | // Install plugin: 6 | // cordova plugin add cordova-plugin-chrome-apps-sockets-tcp 7 | // 8 | // Compatible with "net.Conn" interface. 9 | // 10 | // (Incomplete implementation, missing "setNoDelay", "getSockets", "secures") 11 | package tcpsockets 12 | 13 | import ( 14 | "errors" 15 | "fmt" 16 | "io" 17 | "net" 18 | "time" 19 | 20 | "github.com/gopherjs/gopherjs/js" 21 | ) 22 | 23 | var ( 24 | ErrPluginNotFound = errors.New("chrome.sockets.tcp error: Plugin not found") 25 | ErrConnectionTimedOut = errors.New("chrome.sockets.tcp error: A connection attempt timed out") 26 | ErrConnectionClosed = errors.New("chrome.sockets.tcp error: Connection closed") 27 | ErrConnectionReset = errors.New("chrome.sockets.tcp error: Connection reset") 28 | ErrConnectionRefused = errors.New("chrome.sockets.tcp error: Connection refused") 29 | ErrConnectionFailed = errors.New("chrome.sockets.tcp error: Connection failed") 30 | ErrNameNotResolved = errors.New("chrome.sockets.tcp error: The host name could not be resolved") 31 | ErrInternetDisconnected = errors.New("chrome.sockets.tcp error: The Internet connection has been lost") 32 | ErrGenericFailure = errors.New("chrome.sockets.tcp error: A generic failure occurred") 33 | ErrAlreadyConnected = errors.New("chrome.sockets.tcp error: The socket is already connected") 34 | ErrInvalidAddress = errors.New("chrome.sockets.tcp error: The IP address or port number is invalid") 35 | ErrUnreachableAddress = errors.New("chrome.sockets.tcp error: The IP address is unreachable") 36 | ErrConnectionWasClosed = errors.New("chrome.sockets.tcp error: A connection was closed") 37 | ErrPipeReadFailed = errors.New("chrome.sockets.tcp error: Cannot read") 38 | ErrKeepAlive = errors.New("chrome.sockets.tcp error: Keep alive error") 39 | ErrWsProtocolError = errors.New("chrome.sockets.tcp error: Websocket protocol error") 40 | ErrAddressInUse = errors.New("chrome.sockets.tcp error: Address is already in use") 41 | ) 42 | 43 | const ( 44 | NotFoundErrVal = -1 45 | GenericFailureVal = -2 46 | AlreadyConnectedVal = -23 47 | ConnectionClosedVal = -100 48 | ConnectionResetVal = -101 49 | ConnectionRefusedVal = -102 50 | ConnectionFailedVal = -104 51 | NameNotResolvedVal = -105 52 | InternetDisconnectedVal = -106 53 | ConnectionTimedOutVal = -118 54 | InvalidAddressVal = -108 55 | UnreachableAddressVal = -109 56 | WsProtocolErrorVal = -145 57 | AddressInUseVal = -147 58 | ) 59 | 60 | func (sTcpError *socketTCPError) Error() error { 61 | switch sTcpError.ResultCode { 62 | case NotFoundErrVal: 63 | return ErrPluginNotFound 64 | case ConnectionClosedVal: 65 | return ErrConnectionClosed 66 | case ConnectionResetVal: 67 | return ErrConnectionReset 68 | case ConnectionRefusedVal: 69 | return ErrConnectionRefused 70 | case ConnectionFailedVal: 71 | return ErrConnectionFailed 72 | case NameNotResolvedVal: 73 | return ErrNameNotResolved 74 | case InternetDisconnectedVal: 75 | return ErrInternetDisconnected 76 | case ConnectionTimedOutVal: 77 | return ErrConnectionTimedOut 78 | case InvalidAddressVal: 79 | return ErrInvalidAddress 80 | case UnreachableAddressVal: 81 | return ErrUnreachableAddress 82 | case GenericFailureVal: 83 | return ErrGenericFailure 84 | case AlreadyConnectedVal: 85 | return ErrAlreadyConnected 86 | case WsProtocolErrorVal: 87 | return ErrWsProtocolError 88 | case AddressInUseVal: 89 | return ErrAddressInUse 90 | } 91 | return fmt.Errorf("Unknown error: %d", sTcpError.ResultCode) 92 | } 93 | 94 | type socketTCPError struct { 95 | ResultCode int 96 | } 97 | 98 | type PipeStruct struct { 99 | w *io.PipeWriter 100 | r *io.PipeReader 101 | } 102 | 103 | type conn struct { 104 | socketID int 105 | ipport string 106 | readPipe PipeStruct 107 | socketError error 108 | } 109 | 110 | type addr struct { 111 | ipport string 112 | } 113 | 114 | func (a addr) Network() string { return "tcp" } 115 | func (a addr) String() string { return a.ipport } 116 | 117 | var instance *js.Object 118 | 119 | func mo() *js.Object { 120 | if instance == nil { 121 | instance = js.Global.Get("chrome").Get("sockets").Get("tcp") 122 | } 123 | return instance 124 | } 125 | 126 | // Create func creates a TCP socket. 127 | func Create() (conn, error) { 128 | if mo() == js.Undefined || mo() == nil { 129 | return conn{}, ErrPluginNotFound 130 | } 131 | 132 | ch := make(chan int) 133 | infoCallback := func(obj *js.Object) { 134 | go func() { ch <- obj.Get("socketId").Int() }() 135 | } 136 | 137 | mo().Call("create", infoCallback) 138 | socketID := <-ch 139 | return conn{socketID: socketID}, nil 140 | } 141 | 142 | func (c *conn) Connect(peerAddress string, peerPort int) (err error) { 143 | ch := make(chan int) 144 | connCallback := func(obj *js.Object) { 145 | go func() { ch <- obj.Int() }() 146 | } 147 | 148 | c.ipport = fmt.Sprintf("%s:%d", peerAddress, peerPort) 149 | mo().Call("connect", c.socketID, peerAddress, peerPort, connCallback) 150 | 151 | readCh := make(chan []byte, 100) 152 | readCallback := func(obj *js.Object) { 153 | res := js.Global.Get("Uint8Array").New(obj.Get("data")).Interface().([]byte) 154 | select { 155 | case readCh <- res: 156 | default: 157 | c.Close() 158 | } 159 | } 160 | 161 | readErrorCh := make(chan *socketTCPError, 1) 162 | readErrorCallback := func(obj *js.Object) { 163 | resultCode := obj.Get("resultCode").Int() 164 | socketTcpErr := &socketTCPError{ResultCode: resultCode} 165 | select { 166 | case readErrorCh <- socketTcpErr: 167 | default: 168 | } 169 | } 170 | 171 | result := <-ch 172 | if result >= 0 { 173 | c.readPipe.r, c.readPipe.w = io.Pipe() 174 | mo().Get("onReceive").Call("addListener", readCallback) 175 | mo().Get("onReceiveError").Call("addListener", readErrorCallback) 176 | 177 | go func() { 178 | exit := false 179 | for { 180 | select { 181 | case receive := <-readCh: 182 | if _, e := c.readPipe.w.Write(receive); e != nil { 183 | err = e 184 | exit = true 185 | } 186 | case res := <-readErrorCh: 187 | err = res.Error() 188 | c.socketError = res.Error() 189 | exit = true 190 | break 191 | } 192 | if exit { 193 | readCh = nil 194 | readErrorCh = nil 195 | c.readPipe.w.Close() 196 | break 197 | } 198 | } 199 | }() 200 | return err 201 | } 202 | return ErrConnectionFailed 203 | } 204 | 205 | func (c conn) Close() error { 206 | mo().Call("disconnect", c.socketID) 207 | return c.socketError 208 | } 209 | 210 | func (c conn) Write(b []byte) (n int, err error) { 211 | type result struct { 212 | res, bytes int 213 | } 214 | ch := make(chan result) 215 | connCallback := func(obj *js.Object) { 216 | go func() { ch <- result{res: obj.Get("resultCode").Int(), bytes: obj.Get("bytesSent").Int()} }() 217 | } 218 | mo().Call("send", c.socketID, js.NewArrayBuffer(b), connCallback) 219 | 220 | res := <-ch 221 | if res.res >= 0 { 222 | return res.bytes, nil 223 | } 224 | return 0, errors.New(fmt.Sprintf("chrome.sockets.tcp error: Send error %d", res.res)) 225 | } 226 | 227 | func (c conn) Read(receive []byte) (n int, err error) { 228 | return c.readPipe.r.Read(receive) 229 | } 230 | 231 | func (c conn) LocalAddr() net.Addr { return addr{} } 232 | func (c conn) RemoteAddr() net.Addr { return addr{ipport: c.ipport} } 233 | 234 | func (c conn) SetDeadline(time.Time) error { return nil } 235 | func (c conn) SetReadDeadline(time.Time) error { return nil } 236 | func (c conn) SetWriteDeadline(time.Time) error { return nil } 237 | 238 | func (c conn) Update(socketID int, properties interface{}, cb func()) { 239 | mo().Call("update", socketID, properties, cb) 240 | } 241 | 242 | func (c conn) SetPaused(paused bool) { 243 | mo().Call("setPaused", c.socketID, paused) 244 | } 245 | 246 | func (c conn) SetKeepAlive(enable bool, delaySeconds int) (int, error) { 247 | ch := make(chan int) 248 | keepAliveCallback := func(obj *js.Object) { 249 | go func() { ch <- obj.Get("result").Int() }() 250 | } 251 | 252 | mo().Call("setKeepAlive", c.socketID, enable, delaySeconds, keepAliveCallback) 253 | 254 | res := <-ch 255 | if res >= 0 { 256 | return res, nil 257 | } 258 | return -1, ErrKeepAlive 259 | } 260 | 261 | func (c conn) GetInfo() interface{} { 262 | ch := make(chan interface{}) 263 | 264 | infoCallback := func(obj *js.Object) { 265 | go func() { ch <- obj.Get("socketInfo").Interface() }() 266 | } 267 | mo().Call("getInfo", c.socketID, infoCallback) 268 | res := <-ch 269 | return res 270 | } 271 | -------------------------------------------------------------------------------- /device/device.go: -------------------------------------------------------------------------------- 1 | // Package device is a GopherJS wrapper for cordova device plugin. 2 | // This plugin provides a public DevInfo var, which describes the device's hardware and software. 3 | // 4 | // Install plugin: 5 | // cordova plugin add cordova-plugin-device 6 | package device 7 | 8 | import ( 9 | "crypto/rand" 10 | "encoding/hex" 11 | 12 | "github.com/gopherjs/gopherjs/js" 13 | "github.com/jaracil/goco" 14 | ) 15 | 16 | var ( 17 | DevInfo *Info // DevInfo is a Instance of device.Info type 18 | ) 19 | 20 | // Info declares device's hardware and software info. 21 | type Info struct { 22 | *js.Object 23 | Cordova string `js:"cordova"` // Version of Cordova running on the device. 24 | Model string `js:"model"` // Name of the device's model or product. The value is set by the device manufacturer and may be different across versions of the same product. 25 | Platform string `js:"platform"` // Device's operating system name. 26 | UUID string `js:"uuid"` // Device's Universally Unique Identifier. 27 | Version string `js:"version"` // Operating system version. 28 | Manufacturer string `js:"manufacturer"` // Device's manufacturer. 29 | IsVirtual bool `js:"isVirtual"` // Whether the device is running on a simulator. 30 | Serial string `js:"serial"` // Device's hardware serial number 31 | } 32 | 33 | func init() { 34 | goco.OnDeviceReady(func() { 35 | DevInfo = &Info{ 36 | Object: js.Global.Get("device"), 37 | } 38 | if DevInfo.Platform == "browser" { 39 | print("In browser platform") 40 | DevInfo.Manufacturer = js.Global.Get("navigator").Get("vendor").String() 41 | if DevInfo.Manufacturer == "" { 42 | DevInfo.Manufacturer = "Mozilla" 43 | } 44 | res := js.Global.Get("localStorage").Get("cordova_browser_uuid") 45 | if res == js.Undefined { 46 | uuid := make([]byte, 16) 47 | rand.Read(uuid) 48 | DevInfo.UUID = hex.EncodeToString(uuid) 49 | js.Global.Get("localStorage").Call("setItem", "cordova_browser_uuid", DevInfo.UUID) 50 | print("Generating new UUID for browser platform: " + DevInfo.UUID) 51 | } else { 52 | DevInfo.UUID = res.String() 53 | print("browser UUID: " + DevInfo.UUID) 54 | } 55 | } 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /diagnostic/diagnostic.go: -------------------------------------------------------------------------------- 1 | // Package diagnostic is a GopherJS wrapper for cordova diagnostic plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova.plugins.diagnostic 5 | package diagnostic 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | "github.com/jaracil/goco" 12 | ) 13 | 14 | // Permissions defines Android permissions 15 | type Permissions struct { 16 | *js.Object 17 | ReadCalendar string `js:"READ_CALENDAR"` 18 | WriteCalendar string `js:"WRITE_CALENDAR"` 19 | Camera string `js:"CAMERA"` 20 | ReadContacts string `js:"READ_CONTACTS"` 21 | WriteContacts string `js:"WRITE_CONTACTS"` 22 | GetAccounts string `js:"GET_ACCOUNTS"` 23 | AccessFineLocation string `js:"ACCESS_FINE_LOCATION"` 24 | AccessCoarseLocation string `js:"ACCESS_COARSE_LOCATION"` 25 | RecordAudio string `js:"RECORD_AUDIO"` 26 | ReadPhoneState string `js:"READ_PHONE_STATE"` 27 | CallPhone string `js:"CALL_PHONE"` 28 | AddVoicemail string `js:"ADD_VOICEMAIL"` 29 | UseSip string `js:"USE_SIP"` 30 | ProcessOutgoingCalls string `js:"PROCESS_OUTGOING_CALLS"` 31 | ReadCallLog string `js:"READ_CALL_LOG"` 32 | WriteCallLog string `js:"WRITE_CALL_LOG"` 33 | SendSMS string `js:"SEND_SMS"` 34 | ReceiveSMS string `js:"RECEIVE_SMS"` 35 | ReadSMS string `js:"READ_SMS"` 36 | ReceiveWapPush string `js:"RECEIVE_WAP_PUSH"` 37 | ReceiveMMS string `js:"RECEIVE_MMS"` 38 | WriteExternalStorage string `js:"WRITE_EXTERNAL_STORAGE"` 39 | ReadExternalStorage string `js:"READ_EXTERNAL_STORAGE"` 40 | BodySensors string `js:"BODY_SENSORS"` 41 | } 42 | 43 | // PermissionStatus defines possible permission status 44 | type PermissionStatus struct { 45 | *js.Object 46 | Granted string `js:"GRANTED"` 47 | Denied string `js:"DENIED"` 48 | DeniedAlways string `js:"DENIED_ALWAYS"` 49 | NotRequested string `js:"NOT_REQUESTED"` 50 | Restricted string `js:"RESTRICTED"` 51 | GrantedWhenInUse string `js:"GRANTED_WHEN_IN_USE"` 52 | } 53 | 54 | // Architectures defines possible hardware architectures 55 | type Architectures struct { 56 | *js.Object 57 | Unknown string `js:"UNKNOWN"` 58 | ArmV6 string `js:"ARMv6"` 59 | ArmV7 string `js:"ARMv7"` 60 | ArmV8 string `js:"ARMv8"` 61 | X86 string `js:"X86"` 62 | X86_64 string `js:"X86_64"` 63 | Mips string `js:"MIPS"` 64 | Mips_64 string `js:"MIPS_64"` 65 | } 66 | 67 | var ( 68 | instance *js.Object 69 | 70 | // PermStatus is an instance of PermissionStatus 71 | PermStatus *PermissionStatus 72 | // Perm is an instance of Permissions 73 | Perm *Permissions 74 | // Arch is an instance of Architectures 75 | Arch *Architectures 76 | ) 77 | 78 | func init() { 79 | goco.OnDeviceReady(func() { 80 | Perm = &Permissions{Object: mo().Get("permission")} 81 | PermStatus = &PermissionStatus{Object: mo().Get("permissionStatus")} 82 | Arch = &Architectures{Object: mo().Get("cpuArchitecture")} 83 | }) 84 | } 85 | 86 | func mo() *js.Object { 87 | if instance == nil { 88 | instance = js.Global.Get("cordova").Get("plugins").Get("diagnostic") 89 | } 90 | return instance 91 | } 92 | 93 | // SwitchToSettings opens settings page for this app. 94 | // Platforms: Android and iOS 95 | // Notes: 96 | // Android: this opens the "App Info" page in the Settings app. 97 | // iOS: this opens the app settings page in the Settings app. This works only on iOS 8+ - iOS 7 and below will return with error. 98 | func SwitchToSettings() (err error) { 99 | ch := make(chan struct{}) 100 | success := func() { 101 | close(ch) 102 | } 103 | fail := func(s string) { 104 | err = errors.New(s) 105 | close(ch) 106 | } 107 | mo().Call("switchToSettings", success, fail) 108 | <-ch 109 | return 110 | } 111 | 112 | // SwitchToWirelessSettings Switches to the wireless settings page in the Settings app. Allows configuration of wireless controls such as Wi-Fi, Bluetooth and Mobile networks. 113 | // Platforms: Android 114 | func SwitchToWirelessSettings() (err error) { 115 | mo().Call("switchToWirelessSettings") 116 | err = nil 117 | return 118 | } 119 | 120 | // SwitchToMobileDataSettings Displays mobile settings to allow user to enable mobile data. 121 | // Platforms: Android and Windows 10 UWP 122 | func SwitchToMobileDataSettings() (err error) { 123 | mo().Call("switchToMobileDataSettings") 124 | err = nil 125 | return 126 | } 127 | 128 | // GetPermissionAuthorizationStatus returns the status of permission 129 | // Platforms: Android 130 | func GetPermissionAuthorizationStatus(perm string) (stat string, err error) { 131 | ch := make(chan struct{}) 132 | success := func(st string) { 133 | stat = st 134 | close(ch) 135 | } 136 | fail := func(s string) { 137 | err = errors.New(s) 138 | close(ch) 139 | } 140 | mo().Call("getPermissionAuthorizationStatus", success, fail, perm) 141 | <-ch 142 | return 143 | } 144 | 145 | // GetPermissionsAuthorizationStatus returns the status of permissions 146 | // Platforms: Android 147 | func GetPermissionsAuthorizationStatus(perms []string) (stat map[string]string, err error) { 148 | ch := make(chan struct{}) 149 | success := func(st map[string]interface{}) { 150 | stat = make(map[string]string) 151 | for k, v := range st { 152 | stat[k] = v.(string) 153 | } 154 | close(ch) 155 | } 156 | fail := func(s string) { 157 | err = errors.New(s) 158 | close(ch) 159 | } 160 | mo().Call("getPermissionsAuthorizationStatus", success, fail, perms) 161 | <-ch 162 | return 163 | } 164 | 165 | // RequestRuntimePermission requests app to be granted authorization for a runtime permission. 166 | // Platforms: Android 167 | // Note: this is intended for Android 6 / API 23 and above. Calling on Android 5 / API 22 and below 168 | // will have no effect as the permissions are already granted at installation time. 169 | func RequestRuntimePermission(perm string) (stat string, err error) { 170 | ch := make(chan struct{}) 171 | success := func(st string) { 172 | stat = st 173 | close(ch) 174 | } 175 | fail := func(s string) { 176 | err = errors.New(s) 177 | close(ch) 178 | } 179 | mo().Call("requestRuntimePermission", success, fail, perm) 180 | <-ch 181 | return 182 | } 183 | 184 | // RequestRuntimePermissions requests app to be granted authorization for multiple runtime permissions. 185 | // Platforms: Android 186 | // Note: this is intended for Android 6 / API 23 and above. Calling on Android 5 / API 22 and below 187 | // will always return GRANTED status as permissions are already granted at installation time. 188 | func RequestRuntimePermissions(perms []string) (stat map[string]string, err error) { 189 | ch := make(chan struct{}) 190 | success := func(st map[string]interface{}) { 191 | stat = make(map[string]string) 192 | for k, v := range st { 193 | stat[k] = v.(string) 194 | } 195 | close(ch) 196 | } 197 | fail := func(s string) { 198 | err = errors.New(s) 199 | close(ch) 200 | } 201 | mo().Call("requestRuntimePermissions", success, fail, perms) 202 | <-ch 203 | return 204 | } 205 | 206 | // IsRequestingPermission indicates if the plugin is currently requesting a runtime permission via the native API. 207 | // Platforms: Android 208 | func IsRequestingPermission() bool { 209 | return mo().Call("isRequestingPermission").Bool() 210 | } 211 | 212 | // IsDataRoamingEnabled checks if the device data roaming setting is enabled. Returns true if data roaming is enabled. 213 | // Platforms: Android 214 | func IsDataRoamingEnabled() (res bool, err error) { 215 | ch := make(chan struct{}) 216 | success := func(st bool) { 217 | res = st 218 | close(ch) 219 | } 220 | fail := func(s string) { 221 | err = errors.New(s) 222 | close(ch) 223 | } 224 | mo().Call("isDataRoamingEnabled", success, fail) 225 | <-ch 226 | return 227 | } 228 | 229 | // IsADBModeEnabled checks if the device setting for ADB(debug) is switched on. Returns true if ADB(debug) setting is switched on. 230 | // Platforms: Android 231 | func IsADBModeEnabled() (res bool, err error) { 232 | ch := make(chan struct{}) 233 | success := func(st bool) { 234 | res = st 235 | close(ch) 236 | } 237 | fail := func(s string) { 238 | err = errors.New(s) 239 | close(ch) 240 | } 241 | mo().Call("isADBModeEnabled", success, fail) 242 | <-ch 243 | return 244 | } 245 | 246 | // IsDeviceRooted checks if the device is rooted. Returns true if the device is rooted. 247 | // Platforms: Android 248 | func IsDeviceRooted() (res bool, err error) { 249 | ch := make(chan struct{}) 250 | success := func(st bool) { 251 | res = st 252 | close(ch) 253 | } 254 | fail := func(s string) { 255 | err = errors.New(s) 256 | close(ch) 257 | } 258 | mo().Call("isDeviceRooted", success, fail) 259 | <-ch 260 | return 261 | } 262 | 263 | // IsBackgroundRefreshAuthorized checks if the application is authorized for background refresh. 264 | // Platforms: iOS 265 | func IsBackgroundRefreshAuthorized() (res bool, err error) { 266 | ch := make(chan struct{}) 267 | success := func(st bool) { 268 | res = st 269 | close(ch) 270 | } 271 | fail := func(s string) { 272 | err = errors.New(s) 273 | close(ch) 274 | } 275 | mo().Call("isBackgroundRefreshAuthorized", success, fail) 276 | <-ch 277 | return 278 | } 279 | 280 | // GetBackgroundRefreshStatus returns the background refresh authorization status for the application. 281 | // Platforms: iOS 282 | func GetBackgroundRefreshStatus() (res string, err error) { 283 | ch := make(chan struct{}) 284 | success := func(st string) { 285 | res = st 286 | close(ch) 287 | } 288 | fail := func(s string) { 289 | err = errors.New(s) 290 | close(ch) 291 | } 292 | mo().Call("getBackgroundRefreshStatus", success, fail) 293 | <-ch 294 | return 295 | } 296 | 297 | // GetArchitecture returns the CPU architecture of the current device. 298 | // Platforms: Android and iOS 299 | func GetArchitecture() (res string, err error) { 300 | ch := make(chan struct{}) 301 | success := func(st string) { 302 | res = st 303 | close(ch) 304 | } 305 | fail := func(s string) { 306 | err = errors.New(s) 307 | close(ch) 308 | } 309 | mo().Call("getArchitecture", success, fail) 310 | <-ch 311 | return 312 | } 313 | 314 | // Restart restarts the application. By default, a "warm" restart will be performed in which the main Cordova activity 315 | // is immediately restarted, causing the Webview instance to be recreated. 316 | // 317 | // However, if the cold parameter is set to true, then the application will be "cold" restarted, meaning a system exit 318 | // will be performed, causing the entire application to be restarted. This is useful if you want to fully reset the native 319 | // application state but will cause the application to briefly disappear and re-appear. 320 | // Platforms: Android 321 | func Restart(cold bool) (err error) { 322 | ch := make(chan struct{}) 323 | fail := func(s string) { 324 | err = errors.New(s) 325 | close(ch) 326 | } 327 | mo().Call("restart", fail, cold) 328 | <-ch 329 | return 330 | } 331 | 332 | // EnableDebug enables debug mode, which logs native debug messages to the native and JS consoles. 333 | // Platforms: Android and iOS 334 | func EnableDebug() { 335 | ch := make(chan struct{}) 336 | success := func() { 337 | close(ch) 338 | } 339 | mo().Call("enableDebug", success) 340 | <-ch 341 | return 342 | } 343 | -------------------------------------------------------------------------------- /diagnostic/location/location.go: -------------------------------------------------------------------------------- 1 | // Package location is a GopherJS wrapper for cordova diagnostic/location plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova.plugins.diagnostic 5 | package location 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | "github.com/jaracil/goco" 12 | ) 13 | 14 | // Modes defines Android location modes 15 | type Modes struct { 16 | *js.Object 17 | HighAccuracy string `js:"HIGH_ACCURACY"` 18 | BatterySaving string `js:"BATTERY_SAVING"` 19 | DeviceOnly string `js:"DEVICE_ONLY"` 20 | LocationOff string `js:"LOCATION_OFF"` 21 | } 22 | 23 | var ( 24 | instance *js.Object 25 | 26 | // Mode is an instance of Modes 27 | Mode *Modes 28 | ) 29 | 30 | func init() { 31 | goco.OnDeviceReady(func() { 32 | Mode = &Modes{Object: mo().Get("locationMode")} 33 | }) 34 | } 35 | 36 | func mo() *js.Object { 37 | if instance == nil { 38 | instance = js.Global.Get("cordova").Get("plugins").Get("diagnostic") 39 | } 40 | return instance 41 | } 42 | 43 | // IsLocationAvailable returns true when location is available. 44 | // Platforms: Android, iOS and Windows 10 UWP 45 | func IsLocationAvailable() (res bool, err error) { 46 | ch := make(chan struct{}) 47 | success := func(st bool) { 48 | res = st 49 | close(ch) 50 | } 51 | fail := func(s string) { 52 | err = errors.New(s) 53 | close(ch) 54 | } 55 | mo().Call("isLocationAvailable", success, fail) 56 | <-ch 57 | return 58 | } 59 | 60 | // IsLocationEnabled returns true if the device setting for location is on. 61 | // On Android this returns true if Location Mode is switched on. 62 | // On iOS this returns true if Location Services is switched on. 63 | // Platforms: Android and iOS 64 | func IsLocationEnabled() (res bool, err error) { 65 | ch := make(chan struct{}) 66 | success := func(st bool) { 67 | res = st 68 | close(ch) 69 | } 70 | fail := func(s string) { 71 | err = errors.New(s) 72 | close(ch) 73 | } 74 | mo().Call("isLocationEnabled", success, fail) 75 | <-ch 76 | return 77 | } 78 | 79 | // IsGpsLocationAvailable checks if high-accuracy locations are available to the app from GPS hardware. 80 | // Returns true if Location mode is enabled and is set to "Device only" or "High accuracy" AND if the app is authorized to use location. 81 | // Platforms: Android 82 | func IsGpsLocationAvailable() (res bool, err error) { 83 | ch := make(chan struct{}) 84 | success := func(st bool) { 85 | res = st 86 | close(ch) 87 | } 88 | fail := func(s string) { 89 | err = errors.New(s) 90 | close(ch) 91 | } 92 | mo().Call("isGpsLocationAvailable", success, fail) 93 | <-ch 94 | return 95 | } 96 | 97 | // IsGpsLocationEnabled checks if the device location setting is set to return high-accuracy locations from GPS hardware. 98 | // Platforms: Android 99 | func IsGpsLocationEnabled() (res bool, err error) { 100 | ch := make(chan struct{}) 101 | success := func(st bool) { 102 | res = st 103 | close(ch) 104 | } 105 | fail := func(s string) { 106 | err = errors.New(s) 107 | close(ch) 108 | } 109 | mo().Call("isGpsLocationEnabled", success, fail) 110 | <-ch 111 | return 112 | } 113 | 114 | // IsNetworkLocationAvailable checks if low-accuracy locations are available to the app from network triangulation/WiFi access points. 115 | // Platforms: Android 116 | func IsNetworkLocationAvailable() (res bool, err error) { 117 | ch := make(chan struct{}) 118 | success := func(st bool) { 119 | res = st 120 | close(ch) 121 | } 122 | fail := func(s string) { 123 | err = errors.New(s) 124 | close(ch) 125 | } 126 | mo().Call("isNetworkLocationAvailable", success, fail) 127 | <-ch 128 | return 129 | } 130 | 131 | // IsNetworkLocationEnabled checks if location mode is set to return low-accuracy locations from network triangulation/WiFi access points. 132 | // Platforms: Android 133 | func IsNetworkLocationEnabled() (res bool, err error) { 134 | ch := make(chan struct{}) 135 | success := func(st bool) { 136 | res = st 137 | close(ch) 138 | } 139 | fail := func(s string) { 140 | err = errors.New(s) 141 | close(ch) 142 | } 143 | mo().Call("isNetworkLocationEnabled", success, fail) 144 | <-ch 145 | return 146 | } 147 | 148 | // GetLocationMode returns the current location mode setting for the device. 149 | // Platforms: Android 150 | func GetLocationMode() (res string, err error) { 151 | ch := make(chan struct{}) 152 | success := func(st string) { 153 | res = st 154 | close(ch) 155 | } 156 | fail := func(s string) { 157 | err = errors.New(s) 158 | close(ch) 159 | } 160 | mo().Call("getLocationMode", success, fail) 161 | <-ch 162 | return 163 | } 164 | 165 | // IsLocationAuthorized checks if the application is authorized to use location. 166 | // Platforms: Android and iOS 167 | func IsLocationAuthorized() (res bool, err error) { 168 | ch := make(chan struct{}) 169 | success := func(st bool) { 170 | res = st 171 | close(ch) 172 | } 173 | fail := func(s string) { 174 | err = errors.New(s) 175 | close(ch) 176 | } 177 | mo().Call("isLocationAuthorized", success, fail) 178 | <-ch 179 | return 180 | } 181 | 182 | // GetLocationAuthorizationStatus returns the location authorization status for the application. 183 | // Platforms: Android and iOS 184 | func GetLocationAuthorizationStatus() (res string, err error) { 185 | ch := make(chan struct{}) 186 | success := func(st string) { 187 | res = st 188 | close(ch) 189 | } 190 | fail := func(s string) { 191 | err = errors.New(s) 192 | close(ch) 193 | } 194 | mo().Call("getLocationAuthorizationStatus", success, fail) 195 | <-ch 196 | return 197 | } 198 | 199 | // RequestLocationAuthorization requests location authorization for the application. 200 | // Platforms: Android and iOS 201 | func RequestLocationAuthorization(mode ...[]string) (res string, err error) { 202 | ch := make(chan struct{}) 203 | success := func(st string) { 204 | res = st 205 | close(ch) 206 | } 207 | fail := func(s string) { 208 | err = errors.New(s) 209 | close(ch) 210 | } 211 | if len(mode) == 0 { 212 | mo().Call("requestLocationAuthorization", success, fail) 213 | } else { 214 | mo().Call("requestLocationAuthorization", success, fail, mode[0]) 215 | } 216 | 217 | <-ch 218 | return 219 | } 220 | 221 | // SwitchToLocationSettings displays the device location settings to allow user to enable location services/change location mode. 222 | // Platforms: Android and Windows 10 UWP 223 | func SwitchToLocationSettings() { 224 | mo().Call("switchToLocationSettings") 225 | } 226 | 227 | // RegisterLocationStateChangeHandler registers a function to be called when a change in Location state occurs. 228 | // Pass in nil value to de-register the currently registered function. 229 | // Platforms: Android and iOS 230 | func RegisterLocationStateChangeHandler(f func(string)) { 231 | mo().Call("registerLocationStateChangeHandler", f) 232 | } 233 | -------------------------------------------------------------------------------- /dialogs/dialogs.go: -------------------------------------------------------------------------------- 1 | // Package dialogs is a GopherJS wrapper for dialogs plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-dialogs 5 | package dialogs 6 | 7 | import "github.com/gopherjs/gopherjs/js" 8 | 9 | var instance *js.Object 10 | 11 | func mo() *js.Object { 12 | if instance == nil { 13 | instance = js.Global.Get("navigator").Get("notification") 14 | } 15 | return instance 16 | } 17 | 18 | // Alert shows a custom dialog box, most Cordova implementations use a native dialog box for this feature, 19 | // but some platforms use the browser alert, which is less customizable. It returns true when the dialog is 20 | // dismissed and false in case of error. 21 | func Alert(message, title, button string) bool { 22 | if mo() == js.Undefined || mo() == nil { 23 | return false 24 | } 25 | 26 | ch := make(chan struct{}) 27 | dismissed := func(_ *js.Object) { 28 | close(ch) 29 | } 30 | mo().Call("alert", message, dismissed, title, button) 31 | 32 | <-ch 33 | return true 34 | } 35 | 36 | // Confirm shows a custom dialog with multiple chooses, it returns the index of the button clicked. Given a button 37 | // slice of ["Cancel", "Ok"] it will be 0 if "Cancel" is clicked. It returns -1 in case of error or when the dialog 38 | // is dismissed without a button press. 39 | func Confirm(message, title string, buttons []string) (index int) { 40 | if mo() == js.Undefined || mo() == nil { 41 | return -1 42 | } 43 | 44 | ch := make(chan struct{}) 45 | dismissed := func(obj *js.Object) { 46 | index = obj.Int() - 1 47 | close(ch) 48 | } 49 | mo().Call("confirm", message, dismissed, title, buttons) 50 | 51 | <-ch 52 | return index 53 | } 54 | 55 | // Prompt shows a native dialog with text-input. It return the index of the button pressed (see Confirm function) and 56 | // also the text-value entered in the prompt. 57 | func Prompt(message, title string, buttons []string, input string) (index int, value string) { 58 | if mo() == js.Undefined || mo() == nil { 59 | return -1, input 60 | } 61 | 62 | ch := make(chan struct{}) 63 | dismissed := func(obj *js.Object) { 64 | index = obj.Get("buttonIndex").Int() - 1 65 | value = obj.Get("input1").String() 66 | close(ch) 67 | } 68 | mo().Call("prompt", message, dismissed, title, buttons, input) 69 | 70 | <-ch 71 | return index, value 72 | } 73 | 74 | // Beep will play a beep sound for N times. 75 | func Beep(times uint){ 76 | if mo() == js.Undefined || mo() == nil || times == 0 { 77 | return 78 | } 79 | 80 | mo().Call("beep", times) 81 | } 82 | -------------------------------------------------------------------------------- /file/file.go: -------------------------------------------------------------------------------- 1 | // Package file is a GopherJS wrapper for cordova file plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-file 5 | package file 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "time" 11 | 12 | "github.com/gopherjs/gopherjs/js" 13 | "github.com/jaracil/goco" 14 | ) 15 | 16 | var ( 17 | ErrNotFound = errors.New("Not found error") 18 | ErrSecurity = errors.New("Security error") 19 | ErrAbort = errors.New("Abort error") 20 | ErrNotReadable = errors.New("Not readable error") 21 | ErrEncoding = errors.New("Encoding error") 22 | ErrNoModificationAllowed = errors.New("No modification allowed error") 23 | ErrInvalidState = errors.New("Invalid state error") 24 | ErrSyntax = errors.New("Syntax error") 25 | ErrInvalidModification = errors.New("Invalid modification error") 26 | ErrQuotaExceeded = errors.New("Quota exceeded error") 27 | ErrTypeMismatch = errors.New("Type mismatch error") 28 | ErrPathExists = errors.New("Path exists error") 29 | ) 30 | 31 | const ( 32 | NotFoundErrVal = 1 33 | SecurityErrVal = 2 34 | AbortErrVal = 3 35 | NotReadableErrVal = 4 36 | EncodingErrVal = 5 37 | NoModificationAllowedErrVal = 6 38 | InvalidStateErrVal = 7 39 | SyntaxErrVal = 8 40 | InvalidModificationErrVal = 9 41 | QuotaExceededErrVal = 10 42 | TypeMismatchErrVal = 11 43 | PathExistsErrVal = 12 44 | ) 45 | 46 | func (fe *FileError) Error() error { 47 | switch fe.Code { 48 | case NotFoundErrVal: 49 | return ErrNotFound 50 | case SecurityErrVal: 51 | return ErrSecurity 52 | case AbortErrVal: 53 | return ErrAbort 54 | case NotReadableErrVal: 55 | return ErrNotReadable 56 | case EncodingErrVal: 57 | return ErrEncoding 58 | case NoModificationAllowedErrVal: 59 | return ErrNoModificationAllowed 60 | case InvalidStateErrVal: 61 | return ErrInvalidState 62 | case SyntaxErrVal: 63 | return ErrSyntax 64 | case InvalidModificationErrVal: 65 | return ErrInvalidModification 66 | case QuotaExceededErrVal: 67 | return ErrQuotaExceeded 68 | case TypeMismatchErrVal: 69 | return ErrTypeMismatch 70 | case PathExistsErrVal: 71 | return ErrPathExists 72 | } 73 | return fmt.Errorf("Unknown error: %d", fe.Code) 74 | } 75 | 76 | type Directories struct { 77 | *js.Object 78 | 79 | // ApplicationDirectory holds read-only directory where the application is installed. (iOS, Android, BlackBerry 10, OSX, windows) 80 | ApplicationDirectory string `js:"applicationDirectory"` 81 | 82 | // ApplicationStorageDirectory holds root directory of the application's sandbox; 83 | // on iOS & windows this location is read-only (but specific subdirectories [like /Documents on iOS or /localState on windows] are read-write). 84 | // All data contained within is private to the app. (iOS, Android, BlackBerry 10, OSX) 85 | ApplicationStorageDirectory string `js:"applicationStorageDirectory"` 86 | 87 | // DataDirectory holds persistent and private data storage within the application's sandbox using internal memory 88 | // (on Android, if you need to use external memory, use .externalDataDirectory). 89 | // On iOS, this directory is not synced with iCloud (use .syncedDataDirectory). (iOS, Android, BlackBerry 10, windows) 90 | DataDirectory string `js:"dataDirectory"` 91 | 92 | // CacheDirectory holds directory for cached data files or any files that your app can re-create easily. 93 | // The OS may delete these files when the device runs low on storage, nevertheless, apps should not rely on the OS to delete files in here. 94 | // (iOS, Android, BlackBerry 10, OSX, windows) 95 | CacheDirectory string `js:"cacheDirectory"` 96 | 97 | // ExternalApplicationStorageDirectory holds application space on external storage. (Android) 98 | ExternalApplicationStorageDirectory string `js:"externalApplicationStorageDirectory"` 99 | 100 | // ExternalDataDirectory holds where to put app-specific data files on external storage. (Android) 101 | ExternalDataDirectory string `js:"externalDataDirectory"` 102 | 103 | // ExternalCacheDirectory holds application cache on external storage. (Android) 104 | ExternalCacheDirectory string `js:"externalCacheDirectory"` 105 | 106 | // ExternalRootDirectory holds external storage (SD card) root. (Android, BlackBerry 10) 107 | ExternalRootDirectory string `js:"externalRootDirectory"` 108 | 109 | // TempDirectory holds temp directory that the OS can clear at will. Do not rely on the OS to clear this directory; 110 | // your app should always remove files as applicable. (iOS, OSX, windows) 111 | TempDirectory string `js:"tempDirectory"` 112 | 113 | // SyncedDataDirectory holds directory holding app-specific files that should be synced (e.g. to iCloud). (iOS, windows) 114 | SyncedDataDirectory string `js:"syncedDataDirectory"` 115 | 116 | // DocumentsDirectory holds directory holding files private to the app, but that are meaningful to other application 117 | // (e.g. Office files). Note that for OSX this is the user's ~/Documents directory. (iOS, OSX) 118 | DocumentsDirectory string `js:"documentsDirectory"` 119 | 120 | // SharedDirectory holds directory holding files globally available to all applications (BlackBerry 10) 121 | SharedDirectory string `js:"sharedDirectory"` 122 | } 123 | 124 | var instance *js.Object 125 | 126 | // Dir holds Directories singleton 127 | var Dir *Directories 128 | 129 | func init() { 130 | goco.OnDeviceReady(func() { 131 | Dir = &Directories{Object: mo()} 132 | }) 133 | 134 | } 135 | 136 | func mo() *js.Object { 137 | if instance == nil { 138 | instance = js.Global.Get("cordova").Get("file") 139 | } 140 | return instance 141 | } 142 | 143 | // Metadata of file 144 | type Metadata struct { 145 | *js.Object 146 | ModificationTime time.Time `js:"modificationTime"` 147 | Size int `js:"size"` 148 | } 149 | 150 | // FileSystem type 151 | type FileSystem struct { 152 | *js.Object 153 | Name string `js:"name"` 154 | Root *DirectoryEntry `js:"root"` 155 | } 156 | 157 | type FileError struct { 158 | *js.Object 159 | Code int `js:"code"` 160 | } 161 | 162 | type Flags struct { 163 | Create bool 164 | Exclusive bool 165 | } 166 | 167 | // Entry serves as a base type for the FileEntry and DirectoryEntry types, 168 | // which provide features specific to file system entries representing files and directories, respectively. 169 | type Entry struct { 170 | *js.Object 171 | 172 | // FileSystem object representing the file system in which the entry is located. 173 | FileSystem *FileSystem `js:"filesystem"` 174 | 175 | // FullPath provides the full, absolute path from the file system's root to the entry; 176 | // it can also be thought of as a path which is relative to the root directory, prepended with a "/" character. 177 | FullPath string `js:"fullPath"` 178 | 179 | // IsDirectory returns a boolean which is true if the entry represents a directory; otherwise, it's false. 180 | IsDirectory bool `js:"isDirectory"` 181 | 182 | // IsFile returns a boolean which is true if the entry represents a file. If it's not a file, this value is false. 183 | IsFile bool `js:"isFile"` 184 | 185 | // Name returns a string containing the name of the entry (the final part of the path, after the last "/" character). 186 | Name string `js:"name"` 187 | } 188 | 189 | type DirectoryEntry struct { 190 | *Entry 191 | } 192 | 193 | type FileEntry struct { 194 | *Entry 195 | } 196 | 197 | func (fl *Flags) jsObject() *js.Object { 198 | flags := js.Global.Get("Object").New() 199 | if fl != nil { 200 | flags.Set("create", fl.Create) 201 | flags.Set("exclusive", fl.Exclusive) 202 | } else { 203 | flags.Set("create", false) 204 | flags.Set("exclusive", false) 205 | } 206 | return flags 207 | } 208 | 209 | // AsDirectoryEntry wraps Entry type into DirectoryEntry type. (Ensure IsDirectory property is true before calling this method) 210 | func (e *Entry) AsDirectoryEntry() *DirectoryEntry { 211 | return &DirectoryEntry{Entry: e} 212 | } 213 | 214 | // AsFileEntry wraps Entry type into FileEntry type. (Ensure IsFile property is true before calling this method) 215 | func (e *Entry) AsFileEntry() *FileEntry { 216 | return &FileEntry{Entry: e} 217 | } 218 | 219 | // GetMetadata obtains metadata about the file, such as its modification date and size. 220 | func (e *Entry) GetMetadata() (res *Metadata, err error) { 221 | ch := make(chan struct{}) 222 | success := func(md *Metadata) { 223 | res = md 224 | close(ch) 225 | } 226 | fail := func(e *FileError) { 227 | err = e.Error() 228 | close(ch) 229 | } 230 | e.Call("getMetadata", success, fail) 231 | <-ch 232 | return 233 | } 234 | 235 | // GetParent returns a entry representing the entry's parent directory. 236 | func (e *Entry) GetParent() (res *DirectoryEntry, err error) { 237 | ch := make(chan struct{}) 238 | success := func(de *DirectoryEntry) { 239 | res = de 240 | close(ch) 241 | } 242 | fail := func(e *FileError) { 243 | err = e.Error() 244 | close(ch) 245 | } 246 | e.Call("getParent", success, fail) 247 | <-ch 248 | return 249 | } 250 | 251 | // CopyTo copies the file specified by the entry to a new target location on the file system. 252 | func (e *Entry) CopyTo(target *Entry) (res *Entry, err error) { 253 | ch := make(chan struct{}) 254 | success := func(en *Entry) { 255 | res = en 256 | close(ch) 257 | } 258 | fail := func(e *FileError) { 259 | err = e.Error() 260 | close(ch) 261 | } 262 | e.Call("copyTo", target, success, fail) 263 | <-ch 264 | return 265 | } 266 | 267 | // MoveTo moves the file or directory to a new location on the file system, or renames the file or directory. 268 | func (e *Entry) MoveTo(target *Entry) (res *Entry, err error) { 269 | ch := make(chan struct{}) 270 | success := func(en *Entry) { 271 | res = en 272 | close(ch) 273 | } 274 | fail := func(e *FileError) { 275 | err = e.Error() 276 | close(ch) 277 | } 278 | e.Call("moveTo", target, success, fail) 279 | <-ch 280 | return 281 | } 282 | 283 | // Remove removes the specified file or directory. You can only remove directories which are empty. 284 | func (e *Entry) Remove() (err error) { 285 | ch := make(chan struct{}) 286 | success := func() { 287 | close(ch) 288 | } 289 | fail := func(e *FileError) { 290 | err = e.Error() 291 | close(ch) 292 | } 293 | e.Call("remove", success, fail) 294 | <-ch 295 | return 296 | } 297 | 298 | // Read returns all directory entries. 299 | func (d *DirectoryEntry) Read() (res []*Entry, err error) { 300 | ch := make(chan struct{}) 301 | success := func(entries []*Entry) { 302 | res = entries 303 | close(ch) 304 | } 305 | fail := func(e *FileError) { 306 | err = e.Error() 307 | close(ch) 308 | } 309 | reader := d.Call("createReader") 310 | reader.Call("readEntries", success, fail) 311 | <-ch 312 | return 313 | } 314 | 315 | // GetDirectory returns a DirectoryEntry instance corresponding to a directory contained somewhere within the directory subtree 316 | // rooted at the directory on which it's called. 317 | func (d *DirectoryEntry) GetDirectory(path string, fl *Flags) (res *DirectoryEntry, err error) { 318 | ch := make(chan struct{}) 319 | success := func(de *DirectoryEntry) { 320 | res = de 321 | close(ch) 322 | } 323 | fail := func(e *FileError) { 324 | err = e.Error() 325 | close(ch) 326 | } 327 | d.Call("getDirectory", path, fl.jsObject(), success, fail) 328 | <-ch 329 | return 330 | } 331 | 332 | // GetFile returns a FileEntry instance corresponding to a file contained somewhere within the directory subtree 333 | // rooted at the directory on which it's called. 334 | func (d *DirectoryEntry) GetFile(path string, fl *Flags) (res *FileEntry, err error) { 335 | ch := make(chan struct{}) 336 | success := func(fe *FileEntry) { 337 | res = fe 338 | close(ch) 339 | } 340 | fail := func(e *FileError) { 341 | err = e.Error() 342 | close(ch) 343 | } 344 | d.Call("getFile", path, fl.jsObject(), success, fail) 345 | <-ch 346 | return 347 | } 348 | 349 | func (f *FileEntry) createWriter() (res *js.Object, err error) { 350 | ch := make(chan struct{}) 351 | success := func(ob *js.Object) { 352 | res = ob 353 | close(ch) 354 | } 355 | fail := func(e *FileError) { 356 | err = e.Error() 357 | close(ch) 358 | } 359 | f.Call("createWriter", success, fail) 360 | <-ch 361 | return 362 | } 363 | 364 | func (f *FileEntry) file() (res *js.Object) { 365 | ch := make(chan struct{}) 366 | success := func(ob *js.Object) { 367 | res = ob 368 | close(ch) 369 | } 370 | f.Call("file", success) 371 | <-ch 372 | return 373 | } 374 | 375 | func (f *FileEntry) Write(data []byte) (err error) { 376 | writer, err := f.createWriter() 377 | if err != nil { 378 | return err 379 | } 380 | ch := make(chan struct{}) 381 | success := func() { 382 | close(ch) 383 | } 384 | fail := func(e *FileError) { 385 | err = e.Error() 386 | close(ch) 387 | } 388 | writer.Set("onwriteend", success) 389 | writer.Set("onerror", fail) 390 | buffer := js.Global.Get("Uint8Array").New(data).Get("buffer") 391 | blob := js.Global.Get("Blob").New([]*js.Object{buffer}, map[string]interface{}{"type": ""}) 392 | writer.Call("write", blob) 393 | <-ch 394 | return 395 | } 396 | 397 | func (f *FileEntry) Read() (res []byte, err error) { 398 | reader := js.Global.Get("FileReader").New() 399 | blob := f.file() 400 | ch := make(chan struct{}) 401 | success := func() { 402 | arrayBuffer := reader.Get("result") 403 | res = js.Global.Get("Uint8Array").New(arrayBuffer).Interface().([]byte) 404 | close(ch) 405 | } 406 | fail := func(e *FileError) { 407 | err = e.Error() 408 | close(ch) 409 | } 410 | reader.Set("onloadend", success) 411 | reader.Set("onerror", fail) 412 | reader.Call("readAsArrayBuffer", blob) 413 | <-ch 414 | return 415 | } 416 | 417 | // ToURL creates and returns a URL which identifies the entry. 418 | func (e *Entry) ToURL() (res string) { 419 | return e.Call("toURL").String() 420 | } 421 | 422 | // ResolveLocalFileSystemURL retrieves a Entry instance based on it's local URL 423 | func ResolveLocalFileSystemURL(url string) (res *Entry, err error) { 424 | ch := make(chan struct{}) 425 | success := func(ob *js.Object) { 426 | res = &Entry{Object: ob} 427 | close(ch) 428 | } 429 | fail := func(e *FileError) { 430 | err = e.Error() 431 | close(ch) 432 | } 433 | js.Global.Call("resolveLocalFileSystemURL", url, success, fail) 434 | <-ch 435 | return 436 | } 437 | 438 | // RequestFileSystem requests a file system where data should be stored. 439 | // typ is the storage type of the file system. 440 | // size is the storage space—in bytes—that you need for your app. 441 | func RequestFileSystem(typ int, size int) (res *FileSystem, err error) { 442 | ch := make(chan struct{}) 443 | success := func(ob *js.Object) { 444 | res = &FileSystem{Object: ob} 445 | close(ch) 446 | } 447 | fail := func(e *FileError) { 448 | err = e.Error() 449 | close(ch) 450 | } 451 | js.Global.Call("requestFileSystem", typ, size, success, fail) 452 | <-ch 453 | return 454 | } 455 | -------------------------------------------------------------------------------- /geolocation/geolocation.go: -------------------------------------------------------------------------------- 1 | // Package geolocation is a GopherJS wrapper for cordova geolocation plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-geolocation 5 | package geolocation 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // Coords defines a set of geographic coordinates. 14 | type Coords struct { 15 | *js.Object 16 | Latitude float64 `js:"latitude"` // Latitude in decimal degrees. 17 | Longitude float64 `js:"longitude"` // Longitude in decimal degrees. 18 | Altitude float64 `js:"altitude"` // Height of the position in meters above the ellipsoid. 19 | Accuracy float64 `js:"accuracy"` // Accuracy level of the latitude and longitude coordinates in meters. 20 | AltitudeAccuracy float64 `js:"altitudeAccuracy"` // Accuracy level of the altitude coordinate in meters. 21 | Heading float64 `js:"heading"` // Direction of travel, specified in degrees counting clockwise relative to the true north. 22 | Speed float64 `js:"speed"` // Current ground speed of the device, specified in meters per second. 23 | } 24 | 25 | // Position defines coordinates and timestamp. 26 | type Position struct { 27 | *js.Object 28 | Coords *Coords `js:"coords"` 29 | Timestamp int64 `js:"timestamp"` // Milliseconds from Unix epoch 30 | } 31 | 32 | // Watcher type monitors position changes 33 | type Watcher struct { 34 | *js.Object 35 | } 36 | 37 | var instance *js.Object 38 | 39 | func mo() *js.Object { 40 | if instance == nil { 41 | instance = js.Global.Get("navigator").Get("geolocation") 42 | } 43 | return instance 44 | } 45 | 46 | // CurrentPosition returns current device's position. 47 | // Options must be map[string]interface{} type. 48 | // See https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-geolocation/index.html#options for available options. 49 | func CurrentPosition(options interface{}) (pos *Position, err error) { 50 | ch := make(chan struct{}) 51 | success := func(p *Position) { 52 | pos = p 53 | close(ch) 54 | } 55 | fail := func(obj *js.Object) { 56 | err = errors.New(obj.Get("message").String()) 57 | close(ch) 58 | } 59 | 60 | mo().Call("getCurrentPosition", success, fail, options) 61 | <-ch 62 | return 63 | } 64 | 65 | // NewWatcher creates new position tracking watcher. 66 | // Options must be map[string]interface{} type. 67 | // See https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-geolocation/index.html#options for available options. 68 | func NewWatcher(cb func(pos *Position, err error), options interface{}) *Watcher { 69 | success := func(p *Position) { 70 | cb(p, nil) 71 | } 72 | 73 | fail := func(obj *js.Object) { 74 | err := errors.New(obj.Get("message").String()) 75 | cb(nil, err) 76 | } 77 | 78 | id := mo().Call("watchPosition", success, fail, options) 79 | return &Watcher{Object: id} 80 | } 81 | 82 | // Close cancels tracking watcher 83 | func (w *Watcher) Close() { 84 | mo().Call("clearWatch", w) 85 | } 86 | -------------------------------------------------------------------------------- /globalization/globalization.go: -------------------------------------------------------------------------------- 1 | // Package globalization is a GopherJS wrapper for cordova cordova-plugin-globalization. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-globalization 5 | // 6 | // (Noncomplete implementation) 7 | package globalization 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/gopherjs/gopherjs/js" 13 | ) 14 | 15 | // DatePatternInfo is info returned on GetDatePattern 16 | type DatePatternInfo struct { 17 | Pattern string 18 | Timezone string 19 | IANATimezone string 20 | UTCOffset int 21 | DSTOffset int 22 | } 23 | 24 | var instance *js.Object 25 | 26 | func mo() *js.Object { 27 | if instance == nil { 28 | instance = js.Global.Get("navigator").Get("globalization") 29 | } 30 | return instance 31 | } 32 | 33 | // GetPreferredLanguage downloads an update 34 | func GetPreferredLanguage() (lang string, err error) { 35 | if mo() == nil { 36 | return "", errors.New("Cannot find navigator.globalization object") 37 | } 38 | 39 | ch := make(chan struct{}) 40 | mo().Call("getPreferredLanguage", 41 | func(cbLang *js.Object) { 42 | lang = cbLang.Get("value").String() 43 | close(ch) 44 | }, 45 | func() { 46 | err = errors.New("Error getting preferred language") 47 | close(ch) 48 | }) 49 | <-ch 50 | 51 | return lang, err 52 | } 53 | 54 | // GetDatePattern returns info about date formating 55 | func GetDatePattern() (info *DatePatternInfo, err error) { 56 | if mo() == nil { 57 | return nil, errors.New("Cannot find navigator.globalization object") 58 | } 59 | 60 | ch := make(chan struct{}) 61 | mo().Call("getDatePattern", 62 | func(jsInfo *js.Object) { 63 | info = &DatePatternInfo{ 64 | Pattern: jsInfo.Get("pattern").String(), 65 | Timezone: jsInfo.Get("timezone").String(), 66 | IANATimezone: jsInfo.Get("iana_timezone").String(), 67 | UTCOffset: jsInfo.Get("utc_offset").Int(), 68 | DSTOffset: jsInfo.Get("dst_offset").Int(), 69 | } 70 | close(ch) 71 | }, 72 | func() { 73 | err = errors.New("Error getting date pattern") 74 | close(ch) 75 | }) 76 | <-ch 77 | 78 | return info, err 79 | } 80 | -------------------------------------------------------------------------------- /goco.go: -------------------------------------------------------------------------------- 1 | // Package goco contains idiomatic Go bindings for cordova. 2 | package goco 3 | 4 | import ( 5 | "github.com/gopherjs/gopherjs/js" 6 | ) 7 | 8 | var ( 9 | deviceReady = false 10 | ) 11 | 12 | // WaitReady waits until cordova api is ready (see deviceready event) 13 | func WaitReady() { 14 | if deviceReady { 15 | return 16 | } 17 | ch := make(chan struct{}, 0) 18 | f := func() { 19 | deviceReady = true 20 | close(ch) 21 | } 22 | OnDeviceReady(f) 23 | <-ch 24 | UnDeviceReady(f) 25 | } 26 | 27 | // OnDeviceReady registers callback function that runs when device is ready 28 | func OnDeviceReady(cb func()) { 29 | js.Global.Get("document").Call("addEventListener", "deviceready", cb, false) 30 | } 31 | 32 | // OnPause registers callback function that runs when app goes to background 33 | func OnPause(cb func()) { 34 | js.Global.Get("document").Call("addEventListener", "pause", cb, false) 35 | } 36 | 37 | // OnResume registers callback function that runs when app goes to foreground 38 | func OnResume(cb func()) { 39 | js.Global.Get("document").Call("addEventListener", "resume", cb, false) 40 | } 41 | 42 | // OnVolumeUpButton registers callback function that runs when volume-up button is pressed 43 | func OnVolumeUpButton(cb func()) { 44 | js.Global.Get("document").Call("addEventListener", "volumeupbutton", cb, false) 45 | } 46 | 47 | // OnVolumeDownButton registers callback function that runs when volume-down button is pressed 48 | func OnVolumeDownButton(cb func()) { 49 | js.Global.Get("document").Call("addEventListener", "volumedownbutton", cb, false) 50 | } 51 | 52 | // OnSearchButton registers callback function that runs when search button is pressed 53 | func OnSearchButton(cb func()) { 54 | js.Global.Get("document").Call("addEventListener", "searchbutton", cb, false) 55 | } 56 | 57 | // OnMenuButton registers callback function that runs when menu button is pressed 58 | func OnMenuButton(cb func()) { 59 | js.Global.Get("document").Call("addEventListener", "menubutton", cb, false) 60 | } 61 | 62 | // UnDeviceReady clears previous OnDeviceReady registration 63 | func UnDeviceReady(cb func()) { 64 | js.Global.Get("document").Call("removeEventListener", "deviceready", cb, false) 65 | } 66 | 67 | // UnPause clears previous OnPause registration 68 | func UnPause(cb func()) { 69 | js.Global.Get("document").Call("removeEventListener", "pause", cb, false) 70 | } 71 | 72 | // UnResume clears previous OnResume registration 73 | func UnResume(cb func()) { 74 | js.Global.Get("document").Call("removeEventListener", "resume", cb, false) 75 | } 76 | 77 | // UnVolumeUpButton clears previous OnVolumeUpButton registration 78 | func UnVolumeUpButton(cb func()) { 79 | js.Global.Get("document").Call("removeEventListener", "volumeupbutton", cb, false) 80 | } 81 | 82 | // UnVolumeDownButton clears previous OnVolumeDownButton registration 83 | func UnVolumeDownButton(cb func()) { 84 | js.Global.Get("document").Call("removeEventListener", "volumedownbutton", cb, false) 85 | } 86 | 87 | // UnSearchButton clears previous OnSearchButton registration 88 | func UnSearchButton(cb func()) { 89 | js.Global.Get("document").Call("removeEventListener", "searchbutton", cb, false) 90 | } 91 | 92 | // UnMenuButton clears previous OnMenuButton registration 93 | func UnMenuButton(cb func()) { 94 | js.Global.Get("document").Call("removeEventListener", "menubutton", cb, false) 95 | } 96 | -------------------------------------------------------------------------------- /hotcode/hotcode.go: -------------------------------------------------------------------------------- 1 | // Package hotcode is a GopherJS wrapper for cordova cordova-hot-code-push. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-hot-code-push 5 | // 6 | // (Noncomplete implementation) 7 | package hotcode 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/gopherjs/gopherjs/js" 14 | ) 15 | 16 | // Options used for FetchUpdate 17 | type Options struct { 18 | *js.Object 19 | ConfigFile string `js:"configFile"` 20 | RequestHeaders map[string]string `js:"requestHeaders"` 21 | } 22 | 23 | var instance *js.Object 24 | 25 | func mo() *js.Object { 26 | if instance == nil { 27 | instance = js.Global.Get("chcp") 28 | } 29 | return instance 30 | } 31 | 32 | // NewOptions creates options object for FetchUpdate 33 | func NewOptions() *Options { 34 | return &Options{Object: js.Global.Get("Object").New()} 35 | } 36 | 37 | // FetchUpdate downloads an update 38 | func FetchUpdate(opts ...*Options) (data interface{}, err error) { 39 | if mo() == nil { 40 | return nil, errors.New("Cannot find chcp object") 41 | } 42 | 43 | m := map[string]interface{}{} 44 | 45 | if len(opts) > 0 { 46 | if opts[0].Get("configFile") != nil { 47 | m["config-file"] = opts[0].Get("configFile") 48 | } 49 | 50 | if opts[0].Get("requestHeaders") != nil { 51 | m["request-headers"] = opts[0].Get("requestHeaders") 52 | } 53 | } 54 | 55 | ch := make(chan struct{}) 56 | mo().Call("fetchUpdate", func(cbErr, cbData *js.Object) { 57 | if cbErr != nil { 58 | err = fmt.Errorf("Error on fetchUpdate: code=%v, description=%v", cbErr.Get("code"), cbErr.Get("description")) 59 | } 60 | data = cbData 61 | close(ch) 62 | }, m) 63 | <-ch 64 | return data, err 65 | } 66 | 67 | // InstallUpdate installs downloaded update 68 | func InstallUpdate() (err error) { 69 | if mo() == nil { 70 | return errors.New("Cannot find chcp object") 71 | } 72 | 73 | ch := make(chan struct{}) 74 | mo().Call("installUpdate", func(cbErr *js.Object) { 75 | if cbErr != nil { 76 | err = fmt.Errorf("Error on installUpdate: code=%v, description=%v", cbErr.Get("code"), cbErr.Get("description")) 77 | } 78 | close(ch) 79 | }) 80 | <-ch 81 | return err 82 | } 83 | -------------------------------------------------------------------------------- /motion/motion.go: -------------------------------------------------------------------------------- 1 | // Package motion is a GopherJS wrapper for cordova device-motion plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-device-motion 5 | package motion 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // Acceleration type with x, y, z axes and timestamp 14 | type Acceleration struct { 15 | *js.Object 16 | X float64 `js:"x"` 17 | Y float64 `js:"y"` 18 | Z float64 `js:"z"` 19 | Timestamp int64 `js:"timestamp"` 20 | } 21 | 22 | // Watcher type monitors acceleration changes 23 | type Watcher struct { 24 | *js.Object 25 | } 26 | 27 | var instance *js.Object 28 | 29 | func mo() *js.Object { 30 | if instance == nil { 31 | instance = js.Global.Get("navigator").Get("accelerometer") 32 | } 33 | return instance 34 | } 35 | 36 | // CurrentAcceleration gets the current acceleration. 37 | func CurrentAcceleration() (acc *Acceleration, err error) { 38 | ch := make(chan struct{}) 39 | success := func(a *Acceleration) { 40 | acc = a 41 | close(ch) 42 | } 43 | fail := func() { 44 | err = errors.New("Error getting accelerometer data") 45 | close(ch) 46 | } 47 | 48 | mo().Call("getCurrentAcceleration", success, fail) 49 | <-ch 50 | return 51 | } 52 | 53 | // NewWatcher creates a new motion watcher 54 | func NewWatcher(cb func(acc *Acceleration, err error), options interface{}) *Watcher { 55 | success := func(a *Acceleration) { 56 | cb(a, nil) 57 | } 58 | 59 | fail := func() { 60 | err := errors.New("Error getting accelerometer data") 61 | cb(nil, err) 62 | } 63 | 64 | id := mo().Call("watchAcceleration", success, fail, options) 65 | return &Watcher{Object: id} 66 | } 67 | 68 | // Close cancels watcher 69 | func (w *Watcher) Close() { 70 | mo().Call("clearWatch", w) 71 | } 72 | -------------------------------------------------------------------------------- /mqtt/mqtt.go: -------------------------------------------------------------------------------- 1 | // Package mqtt is a GopherJS wrapper for 'CordovaMqTTPlugin'. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-mqtt 5 | // cordova plugin add https://github.com/arcoirislabs/cordova-plugin-mqtt.git 6 | package mqtt 7 | 8 | import ( 9 | "errors" 10 | 11 | "github.com/gopherjs/gopherjs/js" 12 | ) 13 | 14 | type DisconnectObject struct { 15 | *js.Object 16 | Success func(obj *js.Object) `js:"success"` 17 | Error func(obj *js.Object) `js:"error"` 18 | } 19 | 20 | type Server struct { 21 | *js.Object 22 | URL string `js:"url"` 23 | Port int `js:"port"` 24 | ClientID string `js:"clientId"` 25 | Success func(obj *js.Object) `js:"success"` 26 | Error func(obj *js.Object) `js:"error"` 27 | } 28 | 29 | type PublishOBject struct { 30 | *js.Object 31 | Topic string `js:"topic"` 32 | Payload string `js:"payload"` 33 | Qos int `js:"qos"` 34 | Retain bool `js:"retain"` 35 | Success func(obj *js.Object) `js:"success"` 36 | Error func(obj *js.Object) `js:"error"` 37 | } 38 | 39 | type UnsubscribeObject struct { 40 | *js.Object 41 | Topic string `js:"topic"` 42 | Success func(obj *js.Object) `js:"success"` 43 | Error func(obj *js.Object) `js:"error"` 44 | } 45 | 46 | type SusbscribeObject struct { 47 | *js.Object 48 | Topic string `js:"topic"` 49 | Qos int `js:"qos"` 50 | Success func(obj *js.Object) `js:"success"` 51 | Error func(obj *js.Object) `js:"error"` 52 | } 53 | 54 | var ( 55 | instance *js.Object 56 | connectedServer *Server 57 | subscribeTopicCh = make(chan *SusbscribeObject) 58 | subscribeTopicChRes = make(chan error) 59 | ) 60 | 61 | func mo() *js.Object { 62 | if instance == nil { 63 | instance = js.Global.Get("cordova").Get("plugins").Get("CordovaMqTTPlugin") 64 | } 65 | return instance 66 | } 67 | 68 | // Connect connects to a MQTT server. Will return an non-nil error if plugin is not installed or there was an error connecting 69 | func Connect(url string, port int, clientID string) (err error) { 70 | if mo() == nil || mo() == js.Undefined { 71 | err = errors.New("Couldn't get 'CordovaMqTTPlugin', make sure plugin is installed") 72 | return err 73 | } 74 | if connectedServer != nil { 75 | Disconnect() 76 | } 77 | server := createServer(url, port, clientID) 78 | ch := make(chan error) 79 | server.Success = func(obj *js.Object) { 80 | connectedServer = server 81 | close(ch) 82 | } 83 | server.Error = func(obj *js.Object) { 84 | err = errors.New(obj.String()) 85 | close(ch) 86 | } 87 | 88 | mo().Call("connect", server) 89 | <-ch 90 | go subscribeTopicQueue() 91 | return 92 | } 93 | 94 | func createServer(url string, port int, clientID string) *Server { 95 | server := &Server{Object: js.Global.Get("Object").New()} 96 | server.URL = url 97 | server.Port = port 98 | server.ClientID = clientID 99 | return server 100 | } 101 | 102 | // Disconnect disconnects from the connected server. 103 | func Disconnect() (err error) { 104 | if connectedServer != nil { 105 | ch := make(chan error) 106 | disc := &DisconnectObject{Object: js.Global.Get("Object").New()} 107 | disc.Success = func(obj *js.Object) { 108 | connectedServer = nil 109 | close(ch) 110 | } 111 | disc.Error = func(obj *js.Object) { 112 | err = errors.New(obj.String()) 113 | close(ch) 114 | } 115 | mo().Call("disconnect", disc) 116 | <-ch 117 | } 118 | return 119 | } 120 | 121 | // SubscribeTopic subscribes to a topic, and calls the function passed as a parameter every time it reads a value from the topic. 122 | func SubscribeTopic(topic string, qos int, resFunc func(string)) error { 123 | if connectedServer == nil { 124 | return errors.New("No server connected") 125 | } 126 | 127 | subs := &SusbscribeObject{Object: js.Global.Get("Object").New()} 128 | subs.Topic = topic 129 | subs.Qos = qos 130 | 131 | subscribeTopicCh <- subs 132 | if err := <-subscribeTopicChRes; err != nil { 133 | return err 134 | } 135 | mo().Call("listen", topic, resFunc) 136 | return nil 137 | } 138 | 139 | func subscribeToTopic(subs *SusbscribeObject) (err error) { 140 | ch := make(chan error) 141 | 142 | subs.Success = func(obj *js.Object) { 143 | close(ch) 144 | } 145 | subs.Error = func(obj *js.Object) { 146 | err = errors.New(obj.String()) 147 | close(ch) 148 | } 149 | 150 | mo().Call("subscribe", subs) 151 | <-ch 152 | return 153 | } 154 | 155 | func subscribeTopicQueue() { 156 | for subscriber := range subscribeTopicCh { 157 | subscribeTopicChRes <- subscribeToTopic(subscriber) 158 | } 159 | } 160 | 161 | // Publish sends the data from payload to the topic passed as a parameter on the connected server 162 | func Publish(topic, payload string, qos int, retain bool) (err error) { 163 | if connectedServer == nil { 164 | return errors.New("No server connected") 165 | } 166 | ch := make(chan error) 167 | pub := &PublishOBject{Object: js.Global.Get("Object").New()} 168 | pub.Topic = topic 169 | pub.Payload = payload 170 | pub.Qos = qos 171 | pub.Retain = retain 172 | pub.Success = func(obj *js.Object) { 173 | close(ch) 174 | } 175 | pub.Error = func(obj *js.Object) { 176 | err = errors.New(obj.String()) 177 | close(ch) 178 | } 179 | mo().Call("publish", pub) 180 | <-ch 181 | return 182 | } 183 | 184 | // UnsubscribeTopic usubscribes and stops reading values from that topic 185 | func UnsubscribeTopic(topic string) (err error) { 186 | if connectedServer == nil { 187 | return errors.New("No server connected") 188 | } 189 | ch := make(chan error) 190 | unsub := &UnsubscribeObject{Object: js.Global.Get("Object").New()} 191 | unsub.Topic = topic 192 | unsub.Success = func(obj *js.Object) { 193 | close(ch) 194 | } 195 | unsub.Error = func(obj *js.Object) { 196 | err = errors.New(obj.String()) 197 | close(ch) 198 | } 199 | mo().Call("unsubscribe", unsub) 200 | return 201 | } 202 | -------------------------------------------------------------------------------- /nativestorage/nativestorage.go: -------------------------------------------------------------------------------- 1 | package nativestorage 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/gopherjs/gopherjs/js" 7 | ) 8 | 9 | var ( 10 | ErrWriteFailed = errors.New("Storage error: Write failed") 11 | ErrNotFound = errors.New("Storage error: Item not found") 12 | ErrNullRef = errors.New("Storage error: Null reference") 13 | ErrUndefined = errors.New("Storage error: Undefined type") 14 | ErrJSON = errors.New("Storage error: JSON error") 15 | ErrParam = errors.New("Storage error: Wrong parameter") 16 | ErrUnknown = errors.New("Storage error: Unknown") 17 | ) 18 | 19 | var instance *js.Object 20 | 21 | func mo() *js.Object { 22 | if instance == nil { 23 | instance = js.Global.Get("NativeStorage") 24 | } 25 | return instance 26 | } 27 | 28 | func safeClose(ch chan struct{}) { 29 | select { 30 | case <- ch: 31 | default: 32 | close(ch) 33 | } 34 | } 35 | 36 | func errorByCode(code int) error { 37 | switch code { 38 | case 1: 39 | return ErrWriteFailed 40 | case 2: 41 | return ErrNotFound 42 | case 3: 43 | return ErrNullRef 44 | case 4: 45 | return ErrUndefined 46 | case 5: 47 | return ErrJSON 48 | case 6: 49 | return ErrParam 50 | } 51 | return ErrUnknown 52 | } 53 | 54 | func SetItem(key string, val interface{}) (err error) { 55 | ch := make(chan struct{}) 56 | success := func() { 57 | safeClose(ch) 58 | } 59 | fail := func(obj *js.Object) { 60 | err = errorByCode(obj.Get("code").Int()) 61 | safeClose(ch) 62 | } 63 | mo().Call("setItem", key, val, success, fail) 64 | <-ch 65 | return 66 | } 67 | 68 | func GetItemJS(key string) (ret *js.Object, err error) { 69 | ch := make(chan struct{}) 70 | success := func(obj *js.Object) { 71 | ret = obj 72 | safeClose(ch) 73 | } 74 | fail := func(obj *js.Object) { 75 | err = errorByCode(obj.Get("code").Int()) 76 | safeClose(ch) 77 | } 78 | mo().Call("getItem", key, success, fail) 79 | <-ch 80 | return 81 | } 82 | 83 | func GetItem(key string) (interface{}, error) { 84 | r, e := GetItemJS(key) 85 | if e != nil { 86 | return nil, e 87 | } 88 | return r.Interface(), nil 89 | } 90 | 91 | func GetInt(key string) (int, error) { 92 | r, e := GetItemJS(key) 93 | if e != nil { 94 | return 0, e 95 | } 96 | return r.Int(), nil 97 | } 98 | 99 | func GetInt64(key string) (int64, error) { 100 | r, e := GetItemJS(key) 101 | if e != nil { 102 | return 0, e 103 | } 104 | return r.Int64(), nil 105 | } 106 | 107 | func GetFloat64(key string) (float64, error) { 108 | r, e := GetItemJS(key) 109 | if e != nil { 110 | return 0, e 111 | } 112 | return r.Float(), nil 113 | } 114 | 115 | func GetString(key string) (string, error) { 116 | r, e := GetItemJS(key) 117 | if e != nil { 118 | return "", e 119 | } 120 | return r.String(), nil 121 | } 122 | 123 | func GetBool(key string) (bool, error) { 124 | r, e := GetItemJS(key) 125 | if e != nil { 126 | return false, e 127 | } 128 | return r.Bool(), nil 129 | } 130 | 131 | func RemoveItem(key string) (err error) { 132 | ch := make(chan struct{}) 133 | success := func() { 134 | safeClose(ch) 135 | } 136 | fail := func(obj *js.Object) { 137 | err = errorByCode(obj.Get("code").Int()) 138 | safeClose(ch) 139 | } 140 | mo().Call("remove", key, success, fail) 141 | <-ch 142 | return 143 | } 144 | 145 | func RemoveAll() (err error) { 146 | ch := make(chan struct{}) 147 | success := func() { 148 | safeClose(ch) 149 | } 150 | fail := func(obj *js.Object) { 151 | err = errorByCode(obj.Get("code").Int()) 152 | safeClose(ch) 153 | } 154 | mo().Call("clear", success, fail) 155 | <-ch 156 | return 157 | } 158 | -------------------------------------------------------------------------------- /netinfo/netinfo.go: -------------------------------------------------------------------------------- 1 | // Package netinfo is a GopherJS wrapper for cordova network-information plugin. 2 | // 3 | // This plugin provides two public vars, "Current" and "Kinds" 4 | // Which contains the device's connection kind and available kinds respectively. 5 | // 6 | // Install plugin: 7 | // cordova plugin add cordova-plugin-network-information 8 | package netinfo 9 | 10 | import ( 11 | "github.com/gopherjs/gopherjs/js" 12 | "github.com/jaracil/goco" 13 | ) 14 | 15 | // ActualKind wraps cordova navigator.connection.type (use netinfo.Current) 16 | type ActualKind struct { 17 | *js.Object 18 | Kind string `js:"type"` // Connection kind (See AvailableKinds type) 19 | } 20 | 21 | // AvailableKinds wraps cordova global Connection object (use netinfo.Kinds) 22 | type AvailableKinds struct { 23 | *js.Object 24 | Unknown string `js:"UNKNOWN"` 25 | Ethernet string `js:"ETHERNET"` 26 | Wifi string `js:"WIFI"` 27 | Cell2G string `js:"CELL_2G"` 28 | Cell3G string `js:"CELL_3G"` 29 | Cell4G string `js:"CELL_4G"` 30 | Cell string `js:"CELL"` 31 | None string `js:"NONE"` 32 | } 33 | 34 | // Current contains actual connection kind 35 | var Current *ActualKind 36 | 37 | // Kinds contains available connection kinds 38 | var Kinds *AvailableKinds 39 | 40 | func init() { 41 | goco.OnDeviceReady(func() { 42 | Current = &ActualKind{Object: js.Global.Get("navigator").Get("connection")} 43 | Kinds = &AvailableKinds{Object: js.Global.Get("Connection")} 44 | }) 45 | 46 | } 47 | 48 | // IsCell returns when actual connection is of kind Cell, Cell2G, Cell3G, Cell4G 49 | func IsCell() bool { 50 | return Current.Kind == Kinds.Cell || Current.Kind == Kinds.Cell2G || Current.Kind == Kinds.Cell3G || Current.Kind == Kinds.Cell4G 51 | } 52 | 53 | // OnOffline registers callback function that runs when device goes offline 54 | func OnOffline(cb func()) { 55 | js.Global.Get("document").Call("addEventListener", "offline", cb, false) 56 | } 57 | 58 | // OnOnline registers callback function that runs when device goes online 59 | func OnOnline(cb func()) { 60 | js.Global.Get("document").Call("addEventListener", "online", cb, false) 61 | } 62 | 63 | // UnOffline clears the previous OnOffline registration 64 | func UnOffline(cb func()) { 65 | js.Global.Get("document").Call("removeEventListener", "offline", cb, false) 66 | } 67 | 68 | // UnOnline clears the previous OnOnline registration 69 | func UnOnline(cb func()) { 70 | js.Global.Get("document").Call("removeEventListener", "online", cb, false) 71 | } 72 | -------------------------------------------------------------------------------- /nfc/nfc.go: -------------------------------------------------------------------------------- 1 | // Package nfc is a GopherJS wrapper for cordova nfc plugin. 2 | // 3 | // (INCOMPLETE IMPLEMENTATION!!!) 4 | // 5 | // Install plugin: 6 | // cordova plugin add phonegap-nfc 7 | package nfc 8 | 9 | import ( 10 | "fmt" 11 | "log" 12 | 13 | "github.com/gopherjs/gopherjs/js" 14 | ) 15 | 16 | // Status is the status of the NFC support 17 | type Status string 18 | 19 | const ( 20 | // NfcEnabled when NFC is enabled 21 | NfcEnabled Status = "ENABLED" 22 | // NoNfc the device doesn't support NFC 23 | NoNfc Status = "NO_NFC" 24 | // NfcDisabled if the user has disabled NFC 25 | NfcDisabled Status = "NFC_DISABLED" 26 | // NoNfcOrNfcDisabled when NFC is not present or disabled (on Windows) 27 | NoNfcOrNfcDisabled Status = "NO_NFC_OR_NFC_DISABLED" 28 | ) 29 | 30 | // Tag is an NFC tag 31 | type Tag struct { 32 | o *js.Object 33 | } 34 | 35 | // GetURL returns tag's URL 36 | func (t *Tag) GetURL() string { 37 | return moNDEF().Get("uriHelper").Call("decodePayload", t.o.Get("ndefMessage").Index(0).Get("payload")).String() 38 | } 39 | 40 | func stringify(obj *js.Object) string { 41 | return js.Global.Get("JSON").Call("stringify", obj).String() 42 | } 43 | 44 | var instanceNFC *js.Object 45 | var instanceNDEF *js.Object 46 | 47 | func moNFC() *js.Object { 48 | fmt.Printf("nfc.moNFC") 49 | if instanceNFC == nil { 50 | instanceNFC = js.Global.Get("nfc") 51 | } 52 | return instanceNFC 53 | } 54 | 55 | func moNDEF() *js.Object { 56 | fmt.Printf("nfc.moNDEF") 57 | if instanceNDEF == nil { 58 | instanceNDEF = js.Global.Get("ndef") 59 | } 60 | return instanceNDEF 61 | } 62 | 63 | // AddMimeTypeListener registers an event listener for NDEF tags matching a specified MIME type. 64 | func AddMimeTypeListener(mimeType string, callback func(*Tag)) (err error) { 65 | ch := make(chan struct{}) 66 | success := func() { 67 | close(ch) 68 | } 69 | fail := func(obj *js.Object) { 70 | err = fmt.Errorf("Error registering mimetype listener: %s", stringify(obj)) 71 | close(ch) 72 | } 73 | cb := func(obj *js.Object) { 74 | tag := Tag{o: obj.Get("tag")} 75 | callback(&tag) 76 | } 77 | 78 | moNFC().Call("addMimeTypeListener", mimeType, cb, success, fail) 79 | <-ch 80 | return 81 | } 82 | 83 | // AddNdefListener registers an event listener for any NDEF tag 84 | func AddNdefListener(callback func(*Tag)) (err error) { 85 | ch := make(chan struct{}) 86 | success := func() { 87 | close(ch) 88 | } 89 | fail := func(obj *js.Object) { 90 | err = fmt.Errorf("Error registering NDEF listener: %s", stringify(obj)) 91 | close(ch) 92 | } 93 | cb := func(obj *js.Object) { 94 | log.Printf("AddNdefListener cb") 95 | tag := Tag{o: obj.Get("tag")} 96 | callback(&tag) 97 | } 98 | 99 | moNFC().Call("addNdefListener", cb, success, fail) 100 | <-ch 101 | return 102 | } 103 | 104 | // BeginSession starts scanning for NFC tags (needed on iOS) 105 | func BeginSession() (err error) { 106 | ch := make(chan struct{}) 107 | success := func() { 108 | close(ch) 109 | } 110 | fail := func(obj *js.Object) { 111 | err = fmt.Errorf("Error beggining NFC session: %s", stringify(obj)) 112 | close(ch) 113 | } 114 | 115 | moNFC().Call("beginSession", success, fail) 116 | <-ch 117 | return 118 | } 119 | 120 | // InvalidateSession stops scanning for NFC tags (needed on iOS) 121 | func InvalidateSession() (err error) { 122 | ch := make(chan struct{}) 123 | success := func() { 124 | close(ch) 125 | } 126 | fail := func(obj *js.Object) { 127 | err = fmt.Errorf("Error stopping NFC session: %s", stringify(obj)) 128 | close(ch) 129 | } 130 | 131 | moNFC().Call("invalidateSession", success, fail) 132 | <-ch 133 | return 134 | } 135 | 136 | // Enabled returns status of NFC 137 | func Enabled() (status Status) { 138 | ch := make(chan struct{}) 139 | success := func() { 140 | status = NfcEnabled 141 | close(ch) 142 | } 143 | fail := func(value string) { 144 | status = Status(value) 145 | close(ch) 146 | } 147 | 148 | moNFC().Call("enabled", success, fail) 149 | <-ch 150 | return 151 | } 152 | 153 | // ShowSettings shows the NFC settings on the device 154 | func ShowSettings() (err error) { 155 | ch := make(chan struct{}) 156 | success := func() { 157 | close(ch) 158 | } 159 | fail := func(obj *js.Object) { 160 | err = fmt.Errorf("Error showing settings: %s", stringify(obj)) 161 | close(ch) 162 | } 163 | 164 | moNFC().Call("showSettings", success, fail) 165 | <-ch 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /notifications/notifications.go: -------------------------------------------------------------------------------- 1 | // Package notifications is a GopherJS wrapper for cordova local-notifications plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add https://github.com/katzer/cordova-plugin-local-notifications 5 | package notifications 6 | 7 | import ( 8 | "time" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // Notification type contains all information about one notification. 14 | type Notification struct { 15 | *js.Object 16 | ID int `js:"id"` // A unique identifier required to clear, cancel, update or retrieve the local notification in the future 17 | Title string `js:"title"` // First row of the notification - Default: Empty string (iOS) or the app name (Android) 18 | Text string `js:"text"` // Second row of the notification - Default: Empty string 19 | Badge int `js:"badge"` // The number currently set as the badge of the app icon in Springboard (iOS) or at the right-hand side of the local notification (Android) - Default: 0 (which means don't show a number) 20 | Sound string `js:"sound"` // Uri of the file containing the sound to play when an alert is displayed - Default: res://platform_default 21 | Silent bool `js:"silent"` // Silent 22 | Priority int `js:"priority"` // Notification's priority 23 | Data string `js:"data"` // Arbitrary data. 24 | Icon string `js:"icon"` // Uri of the icon that is shown in the ticker and notification - Default: res://icon 25 | SmallIcon string `js:"smallIcon"` // Uri of the resource (only res://) to use in the notification layouts. Different classes of devices may return different sizes - Default: res://ic_popup_reminder 26 | Ongoing bool `js:"ongoing"` // Ongoing notification 27 | Led string `js:"led"` // ARGB value that you would like the LED on the device to blink - Default: FFFFFF 28 | Every string `js:"every"` // The interval at which to reschedule the local notification. That can be a value of second, minute, hour, day, week, month or year. 29 | At time.Time // The date and time when the system should deliver the local notification. If the specified value is nil or is a date in the past, the local notification is delivered immediately. 30 | FirstAt time.Time // The date and time when the system should first deliver the local notification. If the specified value is nil or is a date in the past, the local notification is delivered immediately. 31 | 32 | } 33 | 34 | var instance *js.Object 35 | 36 | func mo() *js.Object { 37 | if instance == nil { 38 | instance = js.Global.Get("cordova").Get("plugins").Get("notification").Get("local") 39 | } 40 | return instance 41 | } 42 | 43 | // New returns new notification with default values 44 | func New() *Notification { 45 | return &Notification{Object: js.Global.Get("Object").New()} 46 | } 47 | 48 | // HasPermission determines permission to show local notifications 49 | func HasPermission() (res bool) { 50 | ch := make(chan bool, 1) 51 | success := func(granted bool) { 52 | ch <- granted 53 | } 54 | mo().Call("hasPermission", success) 55 | return <-ch 56 | } 57 | 58 | // RegisterPermission registers permission to show local notifications 59 | func RegisterPermission() (res bool) { 60 | ch := make(chan bool, 1) 61 | success := func(granted bool) { 62 | ch <- granted 63 | } 64 | mo().Call("registerPermission", success) 65 | return <-ch 66 | } 67 | 68 | // Schedule accepts *Notification or []*Notification to schedule. 69 | func Schedule(notif *Notification) { 70 | if !notif.At.IsZero() { 71 | notif.Set("at", notif.At.UnixNano()/1000000) 72 | } 73 | if !notif.FirstAt.IsZero() { 74 | notif.Set("firstAt", notif.FirstAt.UnixNano()/1000000) 75 | } 76 | 77 | ch := make(chan struct{}) 78 | success := func() { 79 | close(ch) 80 | } 81 | mo().Call("schedule", notif, success) 82 | <-ch 83 | } 84 | 85 | // Update accepts *Notification or []*Notification to update. 86 | func Update(notif *Notification) { 87 | ch := make(chan struct{}) 88 | success := func() { 89 | close(ch) 90 | } 91 | mo().Call("update", notif, success) 92 | <-ch 93 | } 94 | 95 | // Clear clears notification by ID. 96 | func Clear(id int) { 97 | ch := make(chan struct{}) 98 | success := func() { 99 | close(ch) 100 | } 101 | mo().Call("clear", id, success) 102 | <-ch 103 | } 104 | 105 | // ClearAll clears all notifications. 106 | func ClearAll() { 107 | ch := make(chan struct{}) 108 | success := func() { 109 | close(ch) 110 | } 111 | mo().Call("clearAll", success) 112 | <-ch 113 | } 114 | 115 | // Cancel cancels notification by ID. 116 | func Cancel(id int) { 117 | ch := make(chan struct{}) 118 | success := func() { 119 | close(ch) 120 | } 121 | mo().Call("cancel", id, success) 122 | <-ch 123 | } 124 | 125 | // CancelAll cancels all notifications. 126 | func CancelAll() { 127 | ch := make(chan struct{}) 128 | success := func() { 129 | close(ch) 130 | } 131 | mo().Call("cancelAll", success) 132 | <-ch 133 | } 134 | 135 | // OnSchedule registers a callback which is invoked when a local notification was scheduled. 136 | func OnSchedule(f func(*Notification, string)) { 137 | mo().Call("on", "schedule", f) 138 | } 139 | 140 | // OnTrigger registers a callback which is invoked when a local notification was triggered. 141 | func OnTrigger(f func(*Notification, string)) { 142 | mo().Call("on", "trigger", f) 143 | } 144 | 145 | // OnUpdate registers a callback which is invoked when a local notification was updated. 146 | func OnUpdate(f func(*Notification, string)) { 147 | mo().Call("on", "update", f) 148 | } 149 | 150 | // OnClick registers a callback which is invoked when a local notification was clicked. 151 | func OnClick(f func(*Notification, string)) { 152 | mo().Call("on", "click", f) 153 | } 154 | 155 | // OnClear registers a callback which is invoked when a local notification was cleared from the notification center. 156 | func OnClear(f func(*Notification, string)) { 157 | mo().Call("on", "clear", f) 158 | } 159 | 160 | // OnCancel registers a callback which is invoked when a local notification was canceled. 161 | func OnCancel(f func(*Notification, string)) { 162 | mo().Call("on", "cancel", f) 163 | } 164 | 165 | // OnClearAll registers a callback which is invoked when all notifications were cleared from the notification center. 166 | func OnClearAll(f func(string)) { 167 | mo().Call("on", "clearall", f) 168 | } 169 | 170 | // OnCancelAll registers a callback which is invoked when all local notification were canceled. 171 | func OnCancelAll(f func(string)) { 172 | mo().Call("on", "cancelall", f) 173 | } 174 | 175 | // IsPresent returns true if notification is still present in the notification center 176 | func IsPresent(id int) (res bool) { 177 | ch := make(chan bool, 1) 178 | success := func(present bool) { 179 | ch <- present 180 | } 181 | mo().Call("isPresent", id, success) 182 | return <-ch 183 | } 184 | 185 | // IsScheduled returns true if local notification was scheduled but not yet 186 | // triggered and added to the notification center. Repeating local notifications are always in that state. 187 | func IsScheduled(id int) (res bool) { 188 | ch := make(chan bool, 1) 189 | success := func(present bool) { 190 | ch <- present 191 | } 192 | mo().Call("isScheduled", id, success) 193 | return <-ch 194 | } 195 | 196 | // IsTriggered returns true if event has occurred and the local notification is added to the notification center. 197 | func IsTriggered(id int) (res bool) { 198 | ch := make(chan bool, 1) 199 | success := func(present bool) { 200 | ch <- present 201 | } 202 | mo().Call("isTriggered", id, success) 203 | return <-ch 204 | } 205 | 206 | // GetAllIds returns all alive ID's. 207 | func GetAllIds() []int { 208 | ch := make(chan []int, 1) 209 | success := func(s []int) { 210 | ch <- s 211 | } 212 | mo().Call("getAllIds", success) 213 | return <-ch 214 | } 215 | 216 | // GetScheduledIds returns scheduled ID's. 217 | func GetScheduledIds() []int { 218 | ch := make(chan []int, 1) 219 | success := func(s []int) { 220 | ch <- s 221 | } 222 | mo().Call("getScheduledIds", success) 223 | return <-ch 224 | } 225 | 226 | // GetTriggeredIds returns triggered ID's. 227 | func GetTriggeredIds() []int { 228 | ch := make(chan []int, 1) 229 | success := func(s []int) { 230 | ch <- s 231 | } 232 | mo().Call("getTriggeredIds", success) 233 | return <-ch 234 | } 235 | 236 | // GetAll returns all alive notifications. 237 | func GetAll() []*Notification { 238 | ch := make(chan []*Notification, 1) 239 | success := func(s []*Notification) { 240 | ch <- s 241 | } 242 | mo().Call("getAll", success) 243 | return <-ch 244 | } 245 | 246 | // GetByID returns notification by ID 247 | func GetByID(id int) *Notification { 248 | ch := make(chan *Notification, 1) 249 | success := func(n *Notification) { 250 | ch <- n 251 | } 252 | mo().Call("get", id, success) 253 | return <-ch 254 | } 255 | -------------------------------------------------------------------------------- /orientation/orientation.go: -------------------------------------------------------------------------------- 1 | // Package orientation is a GopherJS wrapper for cordova orientation plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-device-orientation 5 | package orientation 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // Heading contains orientation values. 14 | type Heading struct { 15 | *js.Object 16 | MagneticHeading float64 `js:"magneticHeading"` // The heading in degrees from 0-359.99 at a single moment in time. 17 | TrueHeading float64 `js:"trueHeading"` // The heading relative to the geographic North Pole in degrees 0-359.99 at a single moment in time. A negative value indicates that the true heading can't be determined. 18 | HeadingAccuracy float64 `js:"headingAccuracy"` // The deviation in degrees between the reported heading and the true heading. 19 | Timestamp int64 `js:"timestamp"` // Milliseconds from Unix epoch 20 | } 21 | 22 | // Watcher type monitors orientation changes 23 | type Watcher struct { 24 | *js.Object 25 | } 26 | 27 | var instance *js.Object 28 | 29 | func mo() *js.Object { 30 | if instance == nil { 31 | instance = js.Global.Get("navigator").Get("compass") 32 | } 33 | return instance 34 | } 35 | 36 | // CurrentHeading returns current device's heading. 37 | func CurrentHeading() (heading *Heading, err error) { 38 | ch := make(chan struct{}) 39 | success := func(h *Heading) { 40 | heading = h 41 | close(ch) 42 | } 43 | fail := func() { 44 | err = errors.New("Error getting compass data") 45 | close(ch) 46 | } 47 | 48 | mo().Call("getCurrentHeading", success, fail) 49 | <-ch 50 | return 51 | } 52 | 53 | // NewWatcher creates new orientation tracking watcher. 54 | func NewWatcher(cb func(*Heading, error), options map[string]interface{}) *Watcher { 55 | success := func(h *Heading) { 56 | cb(h, nil) 57 | } 58 | 59 | fail := func() { 60 | err := errors.New("Error getting compass data") 61 | cb(nil, err) 62 | } 63 | 64 | id := mo().Call("watchHeading", success, fail, options) 65 | return &Watcher{Object: id} 66 | } 67 | 68 | // Close cancels tracking watcher 69 | func (w *Watcher) Close() { 70 | mo().Call("clearWatch", w) 71 | } 72 | -------------------------------------------------------------------------------- /push/push.go: -------------------------------------------------------------------------------- 1 | // Package push is a GopherJS wrapper for cordova push plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add phonegap-plugin-push 5 | package push 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | // AndroidCfg contains android platform specific configuration 14 | type AndroidCfg struct { 15 | *js.Object 16 | Icon string `js:"icon"` // Optional. The name of a drawable resource to use as the small-icon. The name should not include the extension. 17 | IconColor string `js:"iconColor"` // Optional. Sets the background color of the small icon on Android 5.0 and greater. 18 | Sound bool `js:"sound"` // Optional. If true it plays the sound specified in the push data or the default system sound. 19 | Vibrate bool `js:"vibrate"` // Optional. If true the device vibrates on receipt of notification. 20 | ClearBadge bool `js:"clearBadge"` // Optional. If true the icon badge will be cleared on init and before push messages are processed. 21 | ClearNotifications bool `js:"clearNotifications"` // Optional. If true the app clears all pending notifications when it is closed. 22 | ForceShow bool `js:"forceShow"` // Optional. Controls the behavior of the notification when app is in foreground. If true and app is in foreground, it will show a notification in the notification drawer, the same way as when the app is in background (and on('notification') callback will be called only when the user clicks the notification). When false and app is in foreground, the on('notification') callback will be called immediately. 23 | Topics []string `js:"topics"` // Optional. If the array contains one or more strings each string will be used to subscribe to a FcmPubSub topic. 24 | MessageKey string `js:"messageKey"` // Optional. The key to search for text of notification. 25 | TitleKey string `js:"titleKey"` // Optional. The key to search for title of notification. 26 | } 27 | 28 | // IOSCfg contains IOS platform specific configuration 29 | type IOSCfg struct { 30 | *js.Object 31 | Alert bool `js:"alert"` // Optional. If true the device shows an alert on receipt of notification. 32 | Badge bool `js:"badge"` // Optional. If true the device sets the badge number on receipt of notification. 33 | Sound bool `js:"sound"` // Optional. If true the device plays a sound on receipt of notification. 34 | ClearBadge bool `js:"clearBadge"` // Optional. If true the badge will be cleared on app startup. 35 | FCMSandbox bool `js:"fcmSandbox"` // Whether to use prod or sandbox GCM setting. Defaults to false. 36 | Topics []string `js:"topics"` // Optional. If the array contains one or more strings each string will be used to subscribe to a FcmPubSub topic. 37 | } 38 | 39 | // BrowserCfg contains browser platform specific configuration 40 | type BrowserCfg struct { 41 | *js.Object 42 | PushServiceURL string `js:"pushServiceURL"` // Optional. URL for the push server you want to use. 43 | ApplicationServerKey string `js:"applicationServerKey"` // Optional. Your GCM API key if you are using VAPID keys. 44 | 45 | } 46 | 47 | // Config contains all supported platforms configuration 48 | type Config struct { 49 | *js.Object 50 | Android *AndroidCfg `js:"android"` 51 | IOS *IOSCfg `js:"ios"` 52 | Browser *BrowserCfg `js:"browser"` 53 | } 54 | 55 | // RegInfo contains registration info (see OnRegistration) 56 | type RegInfo struct { 57 | *js.Object 58 | RegistrationID string `js:"registrationId"` // The registration ID provided by the 3rd party remote push service. 59 | RegistrationType string `js:"registrationType"` // The registration type of the 3rd party remote push service. Either FCM or APNS. 60 | } 61 | 62 | // NotifExtData contains notification extra data 63 | type NotifExtData struct { 64 | *js.Object 65 | Foreground bool `js:"foreground"` // Whether the notification was received while the app was in the foreground. 66 | Coldstart bool `js:"coldstart"` // Will be true if the application is started by clicking on the push notification, false if the app is already started. 67 | Dismissed bool `js:"dismissed"` // Is set to true if the notification was dismissed by the user. 68 | } 69 | 70 | // Notification contains notification data 71 | type Notification struct { 72 | *js.Object 73 | Message string `js:"message"` // The text of the push message sent from the 3rd party service. 74 | Title string `js:"title"` // The optional title of the push message sent from the 3rd party service. 75 | Count string `js:"count"` // The number of messages to be displayed in the badge in iOS/Android or message count in the notification shade in Android. For windows, it represents the value in the badge notification which could be a number or a status glyph. 76 | Sound string `js:"sound"` // The name of the sound file to be played upon receipt of the notification. 77 | Image string `js:"image"` // The path of the image file to be displayed in the notification. 78 | LaunchArgs string `js:"launchArgs"` // The args to be passed to the application on launch from push notification. This works when notification is received in background. (Windows Only) 79 | AdditionalData *NotifExtData `js:"additionalData"` // See NotifExtData type 80 | } 81 | 82 | // NotifError contains error message 83 | type NotifError struct { 84 | *js.Object 85 | Mesage string `js:"message"` 86 | } 87 | 88 | // Push object 89 | type Push struct { 90 | *js.Object 91 | } 92 | 93 | var instance *js.Object 94 | 95 | func mo() *js.Object { 96 | if instance == nil { 97 | instance = js.Global.Get("PushNotification") 98 | } 99 | return instance 100 | } 101 | 102 | // NewConfig returns new Config object with default values 103 | func NewConfig() *Config { 104 | cfg := &Config{Object: js.Global.Get("Object").New()} 105 | cfg.Android = &AndroidCfg{Object: js.Global.Get("Object").New()} 106 | cfg.IOS = &IOSCfg{Object: js.Global.Get("Object").New()} 107 | cfg.Browser = &BrowserCfg{Object: js.Global.Get("Object").New()} 108 | return cfg 109 | } 110 | 111 | // New returns Push object. The cfg param is a config object returned by NewConfig and filled with valid data. 112 | func New(cfg *Config) *Push { 113 | obj := mo().Call("init", cfg) 114 | return &Push{Object: obj} 115 | } 116 | 117 | // HasPermission checks whether the push notification permission has been granted. 118 | func HasPermission() (res bool) { 119 | ch := make(chan struct{}) 120 | success := func(obj *js.Object) { 121 | res = obj.Get("isEnabled").Bool() 122 | close(ch) 123 | } 124 | mo().Call("hasPermission", success) 125 | <-ch 126 | return 127 | } 128 | 129 | // OnRegistration registers a function which will be triggered on each successful registration with the 3rd party push service. 130 | func (p *Push) OnRegistration(f func(*RegInfo)) { 131 | p.Call("on", "registration", f) 132 | } 133 | 134 | // OnNotification registers a function which will be triggered each time a push notification is received by a 3rd party push service on the device. 135 | func (p *Push) OnNotification(f func(*Notification)) { 136 | p.Call("on", "notification", f) 137 | } 138 | 139 | // OnError registers a function which will bre triggered when an internal error occurs and the cache is aborted. 140 | func (p *Push) OnError(f func(*NotifError)) { 141 | p.Call("on", "error", f) 142 | } 143 | 144 | // OffRegistration unregisters a function previously registered by OnRegistration function. 145 | func (p *Push) OffRegistration(f func(*RegInfo)) { 146 | p.Call("off", "registration", f) 147 | } 148 | 149 | // OffNotification unregisters a function previously registered by OnNotification function. 150 | func (p *Push) OffNotification(f func(*Notification)) { 151 | p.Call("off", "notification", f) 152 | } 153 | 154 | // OffError unregisters a function previously registered by OnError function. 155 | func (p *Push) OffError(f func(*NotifError)) { 156 | p.Call("off", "error", f) 157 | } 158 | 159 | // UnRegister is used when the application no longer wants to receive push notifications. 160 | // Beware that this cleans up all event handlers previously registered, so you will need to re-register them if you want them to function again without an application reload. 161 | func (p *Push) UnRegister() (err error) { 162 | ch := make(chan struct{}) 163 | success := func() { 164 | close(ch) 165 | } 166 | fail := func() { 167 | err = errors.New("Error on unregister") 168 | close(ch) 169 | } 170 | p.Call("unregister", success, fail) 171 | <-ch 172 | return 173 | } 174 | 175 | // Subscribe is used when the application wants to subscribe a new topic to receive push notifications. 176 | func (p *Push) Subscribe(topic string) (err error) { 177 | ch := make(chan struct{}) 178 | success := func() { 179 | close(ch) 180 | } 181 | fail := func() { 182 | err = errors.New("Error on topic subscribe") 183 | close(ch) 184 | } 185 | p.Call("subscribe", topic, success, fail) 186 | <-ch 187 | return 188 | } 189 | 190 | // UnSubscribe is used when the application no longer wants to receive push notifications from a specific topic but continue to receive other push messages. 191 | func (p *Push) UnSubscribe(topic string) (err error) { 192 | ch := make(chan struct{}) 193 | success := func() { 194 | close(ch) 195 | } 196 | fail := func() { 197 | err = errors.New("Error on topic unsubscribe") 198 | close(ch) 199 | } 200 | p.Call("unsubscribe", topic, success, fail) 201 | <-ch 202 | return 203 | } 204 | 205 | // SetApplicationIconBadgeNumber sets the badge count visible when the app is not running. 206 | func (p *Push) SetApplicationIconBadgeNumber(count int) (err error) { 207 | ch := make(chan struct{}) 208 | success := func() { 209 | close(ch) 210 | } 211 | fail := func() { 212 | err = errors.New("Error on set application icon badge number") 213 | close(ch) 214 | } 215 | p.Call("setApplicationIconBadgeNumber", success, fail, count) 216 | <-ch 217 | return 218 | } 219 | 220 | // GetApplicationIconBadgeNumber gets the current badge count visible when the app is not running. 221 | func (p *Push) GetApplicationIconBadgeNumber() (res int, err error) { 222 | ch := make(chan struct{}) 223 | success := func(n int) { 224 | res = n 225 | close(ch) 226 | } 227 | fail := func() { 228 | err = errors.New("Error on get application icon badge number") 229 | close(ch) 230 | } 231 | p.Call("getApplicationIconBadgeNumber", success, fail) 232 | <-ch 233 | return 234 | } 235 | 236 | // Finish tells the OS that you are done processing a background push notification. 237 | func (p *Push) Finish(id string) (err error) { 238 | ch := make(chan struct{}) 239 | success := func(n int) { 240 | close(ch) 241 | } 242 | fail := func() { 243 | err = errors.New("Error on finish background notification") 244 | close(ch) 245 | } 246 | p.Call("finish", success, fail, id) 247 | <-ch 248 | return 249 | } 250 | 251 | // ClearAllNotifications tells the OS to clear all notifications from the Notification Center. 252 | func (p *Push) ClearAllNotifications() (err error) { 253 | ch := make(chan struct{}) 254 | success := func(n int) { 255 | close(ch) 256 | } 257 | fail := func() { 258 | err = errors.New("Error on clear all notifications") 259 | close(ch) 260 | } 261 | p.Call("clearAllNotifications", success, fail) 262 | <-ch 263 | return 264 | } 265 | -------------------------------------------------------------------------------- /smsreceive/smsreceive.go: -------------------------------------------------------------------------------- 1 | // Package sms-receive is a GopherJS wrapper for cordova plugin sms receive. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-sms-receive 5 | 6 | package smsreceive 7 | 8 | import ( 9 | "errors" 10 | 11 | "github.com/gopherjs/gopherjs/js" 12 | ) 13 | 14 | type Sms struct { 15 | *js.Object 16 | Data SmsData `js:"data"` 17 | } 18 | 19 | type SmsData struct { 20 | *js.Object 21 | Address string `js:"address"` 22 | Body string `js:"body"` 23 | Date int64 `js:"date"` 24 | DateSent int64 `js:"date_sent"` 25 | Read int `js:"read"` 26 | Seen int `js:"seen"` 27 | ServiceCenter string `js:"service_center"` 28 | Status int `js:"status"` 29 | Type int `js:"type"` 30 | } 31 | 32 | var instance *js.Object 33 | 34 | func mo() *js.Object { 35 | if instance == nil { 36 | instance = js.Global.Get("SMSReceive") 37 | } 38 | return instance 39 | } 40 | 41 | // StartWatch method starts listening for incomming SMS and raises an onSMSArrive event when this happens. 42 | func StartWatch() (err error) { 43 | ch := make(chan interface{}) 44 | success := func() { 45 | close(ch) 46 | } 47 | failure := func(e string) { 48 | err = errors.New(e) 49 | close(ch) 50 | } 51 | mo().Call("startWatch", success, failure) 52 | <-ch 53 | return 54 | } 55 | 56 | // StopWatch method stops listening for incomming SMS. Rember always invoke this method when you have got your SMS to avoid memory leaks. 57 | func StopWatch() (err error) { 58 | ch := make(chan interface{}) 59 | success := func() { 60 | close(ch) 61 | } 62 | failure := func(e string) { 63 | err = errors.New(e) 64 | close(ch) 65 | } 66 | mo().Call("stopWatch", success, failure) 67 | <-ch 68 | return 69 | } 70 | 71 | // SubscribeOnSmsArrive creates the event listener for onSMSArrive event. 72 | func SubscribeOnSmsArrive(cb func(*Sms)) { 73 | js.Global.Get("document").Call("addEventListener", "onSMSArrive", cb, false) 74 | } 75 | 76 | // UnsubscribeOnSmsArrive removes the event listener for onSMSArrive event. 77 | func UnsubscribeOnSmsArrive(cb func(*Sms)) { 78 | js.Global.Get("document").Call("removeEventListener", "onSMSArrive", cb, false) 79 | } 80 | -------------------------------------------------------------------------------- /univlinks/univlinks.go: -------------------------------------------------------------------------------- 1 | // Package univlinks is a GopherJS wrapper for cordova-universal-links-plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-universal-links-plugin 5 | // 6 | // (Noncomplete implementation) 7 | package univlinks 8 | 9 | import ( 10 | "github.com/gopherjs/gopherjs/js" 11 | ) 12 | 13 | var instance *js.Object 14 | 15 | func mo() *js.Object { 16 | if instance == nil { 17 | instance = js.Global.Get("universalLinks") 18 | } 19 | return instance 20 | } 21 | 22 | // Subscribe so cb is executed when eventName (defined in config.xml) is emitted when opening a link 23 | func Subscribe(eventName string, cb func(*js.Object)) { 24 | mo().Call("subscribe", eventName, cb) 25 | } 26 | -------------------------------------------------------------------------------- /vibration/vibration.go: -------------------------------------------------------------------------------- 1 | // Package vibration is a GopherJS wrapper for cordova vibration plugin. 2 | // 3 | // Install plugin: 4 | // cordova plugin add cordova-plugin-vibration 5 | package vibration 6 | 7 | import ( 8 | "github.com/gopherjs/gopherjs/js" 9 | ) 10 | 11 | // Vibrate has different functionalities based on parameters passed to it. 12 | // For example: 13 | // Vibrate(3000) // vibrate for 3 seconds 14 | // Vibrate(3000, 1000, 3000) // vibrate for 3 seconds, wait for 1 second, vibrate for 3 seconds 15 | func Vibrate(pat ...interface{}) { 16 | js.Global.Get("navigator").Call("vibrate", pat) 17 | } 18 | --------------------------------------------------------------------------------