2022-10-27 16:14:30 +03:00
|
|
|
//go:build wasm
|
|
|
|
|
|
|
|
package rui
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "embed"
|
2022-11-02 20:08:02 +03:00
|
|
|
"encoding/base64"
|
|
|
|
"path/filepath"
|
2022-11-01 20:13:09 +03:00
|
|
|
"strings"
|
2022-10-27 16:14:30 +03:00
|
|
|
"syscall/js"
|
|
|
|
)
|
|
|
|
|
|
|
|
//go:embed app_wasm.js
|
|
|
|
var wasmScripts string
|
|
|
|
|
|
|
|
type wasmApp struct {
|
|
|
|
params AppParams
|
|
|
|
createContentFunc func(Session) SessionContent
|
|
|
|
session Session
|
2022-11-02 21:05:55 +03:00
|
|
|
bridge webBridge
|
2022-11-01 20:13:09 +03:00
|
|
|
close chan DataObject
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (app *wasmApp) Finish() {
|
|
|
|
app.session.close()
|
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
func wasmLog(text string) {
|
|
|
|
js.Global().Call("log", text)
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
func (app *wasmApp) handleMessage(this js.Value, args []js.Value) any {
|
|
|
|
if len(args) > 0 {
|
|
|
|
if obj := ParseDataText(args[0].String()); obj != nil {
|
|
|
|
switch command := obj.Tag(); command {
|
|
|
|
/*
|
|
|
|
case "startSession":
|
|
|
|
answer := ""
|
2022-11-02 21:05:55 +03:00
|
|
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
|
|
|
if !bridge.writeMessage(answer) {
|
2022-11-01 20:13:09 +03:00
|
|
|
return
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
session.onStart()
|
2022-11-02 21:05:55 +03:00
|
|
|
go sessionEventHandler(session, events, bridge)
|
2022-11-01 20:13:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
case "reconnect":
|
|
|
|
if sessionText, ok := obj.PropertyValue("session"); ok {
|
|
|
|
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
|
|
|
if session = app.sessions[sessionID]; session != nil {
|
2022-11-02 21:05:55 +03:00
|
|
|
session.setBridge(events, bridge)
|
2022-11-01 20:13:09 +03:00
|
|
|
answer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(answer)
|
|
|
|
|
|
|
|
session.writeInitScript(answer)
|
2022-11-02 21:05:55 +03:00
|
|
|
if !bridge.writeMessage(answer.String()) {
|
2022-10-27 16:14:30 +03:00
|
|
|
return
|
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
session.onReconnect()
|
2022-11-02 21:05:55 +03:00
|
|
|
go sessionEventHandler(session, events, bridge)
|
2022-11-01 20:13:09 +03:00
|
|
|
return
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
DebugLogF("Session #%d not exists", sessionID)
|
2022-10-27 16:14:30 +03:00
|
|
|
} else {
|
2022-11-01 20:13:09 +03:00
|
|
|
ErrorLog(`strconv.Atoi(sessionText) error: ` + err.Error())
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
} else {
|
|
|
|
ErrorLog(`"session" key not found`)
|
|
|
|
}
|
|
|
|
|
|
|
|
answer := ""
|
2022-11-02 21:05:55 +03:00
|
|
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
|
|
|
if !bridge.writeMessage(answer) {
|
2022-11-01 20:13:09 +03:00
|
|
|
return
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
session.onStart()
|
2022-11-02 21:05:55 +03:00
|
|
|
go sessionEventHandler(session, events, bridge)
|
2022-11-01 20:13:09 +03:00
|
|
|
}
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
case "disconnect":
|
|
|
|
session.onDisconnect()
|
|
|
|
return
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
case "session-close":
|
|
|
|
session.onFinish()
|
|
|
|
session.App().removeSession(session.ID())
|
2022-11-02 21:05:55 +03:00
|
|
|
bridge.close()
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
*/
|
|
|
|
case "answer":
|
|
|
|
app.session.handleAnswer(obj)
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
case "imageLoaded":
|
|
|
|
app.session.imageManager().imageLoaded(obj, app.session)
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
case "imageError":
|
|
|
|
app.session.imageManager().imageLoadError(obj, app.session)
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
default:
|
|
|
|
app.session.handleEvent(command, obj)
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-01 20:13:09 +03:00
|
|
|
return nil
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
func (app *wasmApp) removeSession(id int) {
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
func (app *wasmApp) createSession() Session {
|
|
|
|
session := newSession(app, 0, "", ParseDataText(js.Global().Call("sessionInfo", "").String()))
|
2022-11-02 21:05:55 +03:00
|
|
|
session.setBridge(app.close, app.bridge)
|
2022-11-01 20:13:09 +03:00
|
|
|
session.setContent(app.createContentFunc(session))
|
|
|
|
return session
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
2022-11-02 20:08:02 +03:00
|
|
|
func (app *wasmApp) init(params AppParams) {
|
|
|
|
|
|
|
|
app.params = params
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
document := js.Global().Get("document")
|
|
|
|
body := document.Call("querySelector", "body")
|
2022-11-02 20:08:02 +03:00
|
|
|
head := document.Call("querySelector", "head")
|
|
|
|
|
|
|
|
meta := document.Call("createElement", "meta")
|
|
|
|
meta.Set("name", "viewport")
|
|
|
|
meta.Set("content", "width=device-width")
|
|
|
|
head.Call("appendChild", meta)
|
|
|
|
|
|
|
|
meta = document.Call("createElement", "base")
|
|
|
|
meta.Set("target", "_blank")
|
|
|
|
meta.Set("rel", "noopener")
|
|
|
|
head.Call("appendChild", meta)
|
|
|
|
|
|
|
|
if params.Icon != "" {
|
|
|
|
if image, ok := resources.images[params.Icon]; ok && image.fs != nil {
|
|
|
|
dataType := map[string]string{
|
|
|
|
".svg": "data:image/svg+xml",
|
|
|
|
".png": "data:image/png",
|
|
|
|
".jpg": "data:image/jpg",
|
|
|
|
".jpeg": "data:image/jpg",
|
|
|
|
".gif": "data:image/gif",
|
|
|
|
}
|
|
|
|
ext := strings.ToLower(filepath.Ext(params.Icon))
|
|
|
|
if prefix, ok := dataType[ext]; ok {
|
|
|
|
if data, err := image.fs.ReadFile(image.path); err == nil {
|
|
|
|
meta = document.Call("createElement", "link")
|
|
|
|
meta.Set("rel", "icon")
|
|
|
|
meta.Set("href", prefix+";base64,"+base64.StdEncoding.EncodeToString(data))
|
|
|
|
head.Call("appendChild", meta)
|
|
|
|
} else {
|
|
|
|
DebugLog(err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
script := document.Call("createElement", "script")
|
|
|
|
script.Set("type", "text/javascript")
|
|
|
|
script.Set("textContent", defaultScripts+wasmScripts)
|
|
|
|
body.Call("appendChild", script)
|
|
|
|
|
|
|
|
js.Global().Set("sendMessage", js.FuncOf(app.handleMessage))
|
|
|
|
|
|
|
|
app.close = make(chan DataObject)
|
|
|
|
app.session = app.createSession()
|
|
|
|
|
|
|
|
style := document.Call("createElement", "style")
|
|
|
|
css := appStyles + app.session.getCurrentTheme().cssText(app.session)
|
|
|
|
css = strings.ReplaceAll(css, `\n`, "\n")
|
|
|
|
css = strings.ReplaceAll(css, `\t`, "\t")
|
|
|
|
style.Set("textContent", css)
|
|
|
|
document.Call("querySelector", "head").Call("appendChild", style)
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
|
|
|
div := document.Call("createElement", "div")
|
|
|
|
div.Set("className", "ruiRoot")
|
|
|
|
div.Set("id", "ruiRootView")
|
|
|
|
viewHTML(app.session.RootView(), buffer)
|
|
|
|
div.Set("innerHTML", buffer.String())
|
|
|
|
body.Call("appendChild", div)
|
|
|
|
|
|
|
|
div = document.Call("createElement", "div")
|
|
|
|
div.Set("className", "ruiPopupLayer")
|
|
|
|
div.Set("id", "ruiPopupLayer")
|
|
|
|
div.Set("onclick", "clickOutsidePopup(event)")
|
|
|
|
div.Set("style", "visibility: hidden;")
|
|
|
|
body.Call("appendChild", div)
|
|
|
|
|
|
|
|
div = document.Call("createElement", "a")
|
|
|
|
div.Set("id", "ruiDownloader")
|
|
|
|
div.Set("download", "")
|
|
|
|
div.Set("style", "display: none;")
|
|
|
|
body.Call("appendChild", div)
|
2022-11-02 20:08:02 +03:00
|
|
|
|
|
|
|
if params.TitleColor != 0 {
|
2022-11-02 21:05:55 +03:00
|
|
|
app.bridge.callFunc("setTitleColor", params.TitleColor.cssString())
|
2022-11-02 20:08:02 +03:00
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
}
|
2022-10-27 16:14:30 +03:00
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
// StartApp - create the new wasmApp and start it
|
|
|
|
func StartApp(addr string, createContentFunc func(Session) SessionContent, params AppParams) {
|
|
|
|
SetDebugLog(wasmLog)
|
|
|
|
SetErrorLog(wasmLog)
|
|
|
|
|
|
|
|
if createContentFunc == nil {
|
|
|
|
return
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|
|
|
|
|
2022-11-01 20:13:09 +03:00
|
|
|
app := new(wasmApp)
|
|
|
|
app.createContentFunc = createContentFunc
|
2022-11-02 21:05:55 +03:00
|
|
|
app.bridge = createWasmBridge()
|
2022-11-01 20:13:09 +03:00
|
|
|
|
2022-11-02 20:08:02 +03:00
|
|
|
app.init(params)
|
2022-11-01 20:13:09 +03:00
|
|
|
<-app.close
|
|
|
|
}
|
|
|
|
|
|
|
|
func FinishApp() {
|
|
|
|
//app.Finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
func OpenBrowser(url string) bool {
|
|
|
|
return false
|
2022-10-27 16:14:30 +03:00
|
|
|
}
|