rui_orig/wasmBridge.go

292 lines
7.7 KiB
Go
Raw Normal View History

2022-11-02 21:05:55 +03:00
//go:build wasm
package rui
import (
"fmt"
"strconv"
2022-11-08 16:31:21 +03:00
"strings"
2022-11-02 21:05:55 +03:00
"syscall/js"
)
type wasmBridge struct {
2022-11-08 16:31:21 +03:00
answer map[int]chan DataObject
answerID int
canvas js.Value
closeEvent chan DataObject
2022-11-02 21:05:55 +03:00
}
2024-03-12 19:32:22 +03:00
func createWasmBridge(close chan DataObject) bridge {
2022-11-02 21:05:55 +03:00
bridge := new(wasmBridge)
bridge.answerID = 1
bridge.answer = make(map[int]chan DataObject)
2022-11-08 16:31:21 +03:00
bridge.closeEvent = close
2022-11-02 21:05:55 +03:00
return bridge
}
func (bridge *wasmBridge) startUpdateScript(htmlID string) bool {
return false
}
func (bridge *wasmBridge) finishUpdateScript(htmlID string) {
}
2022-11-03 14:33:54 +03:00
func (bridge *wasmBridge) printFuncToLog(funcName string, args ...any) {
2022-11-02 21:05:55 +03:00
if ProtocolInDebugLog {
text := funcName + "("
for i, arg := range args {
if i > 0 {
text += fmt.Sprintf(", `%v`", arg)
} else {
text += fmt.Sprintf("`%v`", arg)
}
}
DebugLog(text + ")")
}
2022-11-03 14:33:54 +03:00
}
func (bridge *wasmBridge) callFunc(funcName string, args ...any) bool {
bridge.printFuncToLog(funcName, args...)
2022-11-02 21:05:55 +03:00
js.Global().Call(funcName, args...)
return true
}
func (bridge *wasmBridge) updateInnerHTML(htmlID, html string) {
2022-11-08 16:31:21 +03:00
if ProtocolInDebugLog {
DebugLog(fmt.Sprintf("%s.innerHTML = '%s'", htmlID, html))
}
element := js.Global().Get("document").Call("getElementById", htmlID)
if !element.IsUndefined() && !element.IsNull() {
element.Set("innerHTML", html)
js.Global().Call("scanElementsSize")
}
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) appendToInnerHTML(htmlID, html string) {
2022-11-03 14:33:54 +03:00
if ProtocolInDebugLog {
DebugLog(fmt.Sprintf("%s.innerHTML += '%s'", htmlID, html))
}
element := js.Global().Get("document").Call("getElementById", htmlID)
if !element.IsUndefined() && !element.IsNull() {
oldHtml := element.Get("innerHTML").String()
element.Set("innerHTML", oldHtml+html)
js.Global().Call("scanElementsSize")
}
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) updateCSSProperty(htmlID, property, value string) {
2022-11-03 14:33:54 +03:00
if ProtocolInDebugLog {
DebugLog(fmt.Sprintf("%s.style[%s] = '%s'", htmlID, property, value))
}
element := js.Global().Get("document").Call("getElementById", htmlID)
if !element.IsUndefined() && !element.IsNull() {
element.Get("style").Set(property, value)
js.Global().Call("scanElementsSize")
}
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) updateProperty(htmlID, property string, value any) {
2022-11-08 16:31:21 +03:00
bridge.callFunc("updateProperty", htmlID, property, value)
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) removeProperty(htmlID, property string) {
bridge.callFunc("removeProperty", htmlID, property)
}
func (bridge *wasmBridge) close() {
2022-11-08 16:31:21 +03:00
bridge.closeEvent <- NewDataObject("close")
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) writeMessage(script string) bool {
if ProtocolInDebugLog {
DebugLog("Run script:")
DebugLog(script)
}
window := js.Global().Get("window")
window.Call("execScript", script)
return true
}
2024-03-12 19:32:22 +03:00
func (bridge *wasmBridge) prepareCSS(css string) string {
2022-11-08 16:31:21 +03:00
css = strings.ReplaceAll(css, `\t`, "\t")
css = strings.ReplaceAll(css, `\n`, "\n")
css = strings.ReplaceAll(css, `\'`, "'")
css = strings.ReplaceAll(css, `\"`, "\"")
css = strings.ReplaceAll(css, `\\`, "\\")
2024-03-12 19:32:22 +03:00
return css
}
2022-11-08 16:31:21 +03:00
2024-03-12 19:32:22 +03:00
func (bridge *wasmBridge) appendAnimationCSS(css string) {
2022-11-08 16:31:21 +03:00
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
content := styles.Get("textContent").String()
2024-03-12 19:32:22 +03:00
styles.Set("textContent", content+"\n"+bridge.prepareCSS(css))
2022-11-08 16:31:21 +03:00
}
2024-03-12 19:32:22 +03:00
func (bridge *wasmBridge) setAnimationCSS(css string) {
2022-11-08 16:31:21 +03:00
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
2024-03-12 19:32:22 +03:00
styles.Set("textContent", bridge.prepareCSS(css))
2022-11-08 16:31:21 +03:00
}
2022-11-23 15:10:29 +03:00
func (bridge *wasmBridge) canvasStart(htmlID string) {
2022-11-03 14:33:54 +03:00
if ProtocolInDebugLog {
DebugLog("const ctx = document.getElementById('" + htmlID + "'elementId').getContext('2d');\nctx.save();")
}
2022-11-02 21:05:55 +03:00
bridge.canvas = js.Global().Call("getCanvasContext", htmlID)
2022-11-02 23:16:45 +03:00
if !bridge.canvas.IsNull() {
bridge.canvas.Call("save")
}
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) callCanvasFunc(funcName string, args ...any) {
if !bridge.canvas.IsNull() {
for i, arg := range args {
if array, ok := arg.([]float64); ok {
arr := make([]any, len(array))
for k, x := range array {
arr[k] = x
}
2022-11-02 23:16:45 +03:00
args[i] = js.ValueOf(arr)
2022-11-02 21:05:55 +03:00
}
}
2022-11-03 14:33:54 +03:00
bridge.printFuncToLog("ctx."+funcName, args...)
2022-11-02 21:05:55 +03:00
bridge.canvas.Call(funcName, args...)
}
}
func (bridge *wasmBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
if jsVar, ok := v.(js.Value); ok && !jsVar.IsNull() {
2022-11-03 14:33:54 +03:00
bridge.printFuncToLog(jsVar.String()+"."+funcName, args...)
2022-11-02 21:05:55 +03:00
jsVar.Call(funcName, args...)
}
}
func (bridge *wasmBridge) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
image := js.Global().Get("images").Call("get", url)
2022-11-02 21:22:15 +03:00
if !image.IsUndefined() && !image.IsNull() && !bridge.canvas.IsNull() {
2022-11-03 14:33:54 +03:00
args = append([]any{image}, args...)
result := bridge.canvas.Call(funcName, args...)
2022-11-02 21:05:55 +03:00
if property != "" {
2022-11-03 14:33:54 +03:00
bridge.printFuncToLog("ctx."+property+" = ctx."+funcName, args...)
2022-11-02 21:05:55 +03:00
bridge.canvas.Set(property, result)
2022-11-03 14:33:54 +03:00
} else {
bridge.printFuncToLog("ctx."+funcName, args...)
2022-11-02 21:05:55 +03:00
}
}
}
func (bridge *wasmBridge) createCanvasVar(funcName string, args ...any) any {
if bridge.canvas.IsNull() {
return bridge.canvas
}
2022-11-03 14:33:54 +03:00
result := bridge.canvas.Call(funcName, args...)
bridge.printFuncToLog("var "+result.String()+" = ctx."+funcName, args...)
return result
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) createPath2D(arg string) any {
if arg != "" {
result := bridge.canvas.Call("createPath2D", arg)
bridge.printFuncToLog("var "+result.String()+" = new Path2D", arg)
return result
}
result := bridge.canvas.Call("createPath2D")
bridge.printFuncToLog("var " + result.String() + " = new Path2D")
return result
}
2022-11-02 21:05:55 +03:00
func (bridge *wasmBridge) updateCanvasProperty(property string, value any) {
if !bridge.canvas.IsNull() {
2022-11-03 14:33:54 +03:00
if ProtocolInDebugLog {
DebugLog(fmt.Sprintf("ctx.%s = '%v'", property, value))
}
2022-11-02 21:05:55 +03:00
bridge.canvas.Set(property, value)
}
}
2022-11-23 15:10:29 +03:00
func (bridge *wasmBridge) canvasFinish() {
2022-11-02 23:16:45 +03:00
if !bridge.canvas.IsNull() {
2022-11-03 14:33:54 +03:00
DebugLog("ctx.restore()")
2022-11-02 23:16:45 +03:00
bridge.canvas.Call("restore")
}
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics {
2022-11-02 23:16:45 +03:00
result := TextMetrics{}
canvas := js.Global().Get("document").Call("getElementById", htmlID)
if !canvas.IsUndefined() && !canvas.IsNull() {
context := canvas.Call("getContext", "2d")
if !context.IsUndefined() && !context.IsNull() {
context.Call("save")
context.Set("font", font)
context.Set("textBaseline", "alphabetic")
context.Set("textAlign", "start")
metrics := context.Call("measureText", text)
if !metrics.IsUndefined() && !metrics.IsNull() {
metricsValue := func(name string) float64 {
value := metrics.Get(name)
if !value.IsUndefined() && !value.IsNull() && value.Type() == js.TypeNumber {
return value.Float()
}
return 0
}
result.Width = metricsValue("width")
result.Ascent = metricsValue("actualBoundingBoxAscent")
result.Descent = metricsValue("actualBoundingBoxDescent")
result.Left = metricsValue("actualBoundingBoxLeft")
result.Right = metricsValue("actualBoundingBoxRight")
}
context.Call("restore")
}
}
return result
2022-11-02 21:05:55 +03:00
}
func (bridge *wasmBridge) htmlPropertyValue(htmlID, name string) string {
2022-11-02 23:16:45 +03:00
element := js.Global().Get("document").Call("getElementById", htmlID)
if !element.IsUndefined() && !element.IsNull() {
return element.Get(name).String()
}
2022-11-02 21:05:55 +03:00
return ""
}
func (bridge *wasmBridge) answerReceived(answer DataObject) {
if text, ok := answer.PropertyValue("answerID"); ok {
if id, err := strconv.Atoi(text); err == nil {
if chanel, ok := bridge.answer[id]; ok {
chanel <- answer
delete(bridge.answer, id)
} else {
ErrorLog("Bad answerID = " + text + " (chan not found)")
}
} else {
ErrorLog("Invalid answerID = " + text)
}
} else {
ErrorLog("answerID not found")
}
}
func (bridge *wasmBridge) remoteAddr() string {
return "localhost"
}
2024-03-12 19:32:22 +03:00
func (bridge *wasmBridge) sendResponse() {
}