forked from mbk-lab/rui_orig
Updated wasm support
This commit is contained in:
parent
b4032b31e0
commit
b26525e892
|
@ -200,7 +200,7 @@ func (app *application) startSession(params DataObject, events chan DataObject,
|
|||
|
||||
session := newSession(app, app.nextSessionID(), "", params)
|
||||
session.setBrige(events, brige)
|
||||
if !session.setContent(app.createContentFunc(session), session) {
|
||||
if !session.setContent(app.createContentFunc(session)) {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
|
|
178
appWasm.go
178
appWasm.go
|
@ -4,6 +4,7 @@ package rui
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"strings"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
|
@ -15,83 +16,20 @@ type wasmApp struct {
|
|||
createContentFunc func(Session) SessionContent
|
||||
session Session
|
||||
brige webBrige
|
||||
close chan DataObject
|
||||
}
|
||||
|
||||
func (app *wasmApp) Finish() {
|
||||
app.session.close()
|
||||
}
|
||||
|
||||
func (app *wasmApp) startSession(this js.Value, args []js.Value) interface{} {
|
||||
if app.createContentFunc == nil || len(args) == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
params := ParseDataText(args[0].String())
|
||||
session := newSession(app, 0, "", params)
|
||||
session.setBrige(make(chan DataObject), app.brige)
|
||||
if !session.setContent(app.createContentFunc(session), session) {
|
||||
return nil
|
||||
}
|
||||
|
||||
app.session = session
|
||||
|
||||
answer := allocStringBuilder()
|
||||
defer freeStringBuilder(answer)
|
||||
|
||||
session.writeInitScript(answer)
|
||||
answerText := answer.String()
|
||||
|
||||
if ProtocolInDebugLog {
|
||||
DebugLog("Start session:")
|
||||
DebugLog(answerText)
|
||||
}
|
||||
return nil
|
||||
func wasmLog(text string) {
|
||||
js.Global().Call("log", text)
|
||||
}
|
||||
|
||||
func (app *wasmApp) removeSession(id int) {
|
||||
}
|
||||
|
||||
// StartApp - create the new wasmApp and start it
|
||||
func StartApp(addr string, createContentFunc func(Session) SessionContent, params AppParams) {
|
||||
app := new(wasmApp)
|
||||
app.params = params
|
||||
app.createContentFunc = createContentFunc
|
||||
|
||||
if createContentFunc == nil {
|
||||
return
|
||||
}
|
||||
|
||||
app.brige = createWasmBrige()
|
||||
js.Global().Set("startSession", js.FuncOf(app.startSession))
|
||||
|
||||
/*
|
||||
script := defaultScripts + wasmScripts
|
||||
script = strings.ReplaceAll(script, "\\", `\\`)
|
||||
script = strings.ReplaceAll(script, "\n", `\n`)
|
||||
script = strings.ReplaceAll(script, "\t", `\t`)
|
||||
script = strings.ReplaceAll(script, "\"", `\"`)
|
||||
script = strings.ReplaceAll(script, "'", `\'`)
|
||||
|
||||
js.Global().Call("execScript", `document.getElementById('ruiscript').text += "`+script+`"`)
|
||||
*/
|
||||
|
||||
document := js.Global().Get("document")
|
||||
body := document.Call("querySelector", "body")
|
||||
body.Set("innerHTML", `<div class="ruiRoot" id="ruiRootView"></div>
|
||||
<div class="ruiPopupLayer" id="ruiPopupLayer" style="visibility: hidden;" onclick="clickOutsidePopup(event)"></div>
|
||||
<a id="ruiDownloader" download style="display: none;"></a>`)
|
||||
|
||||
//js.Global().Call("execScript", "initSession()")
|
||||
js.Global().Call("initSession", "")
|
||||
//window.Call("execScript", "initSession()")
|
||||
|
||||
for true {
|
||||
if message, ok := app.brige.readMessage(); ok && app.session != nil {
|
||||
if ProtocolInDebugLog {
|
||||
DebugLog(message)
|
||||
}
|
||||
|
||||
if obj := ParseDataText(message); obj != nil {
|
||||
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":
|
||||
|
@ -161,7 +99,81 @@ func StartApp(addr string, createContentFunc func(Session) SessionContent, param
|
|||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *wasmApp) removeSession(id int) {
|
||||
}
|
||||
|
||||
func (app *wasmApp) createSession() Session {
|
||||
session := newSession(app, 0, "", ParseDataText(js.Global().Call("sessionInfo", "").String()))
|
||||
session.setBrige(app.close, app.brige)
|
||||
session.setContent(app.createContentFunc(session))
|
||||
return session
|
||||
}
|
||||
|
||||
func (app *wasmApp) init() {
|
||||
|
||||
document := js.Global().Get("document")
|
||||
body := document.Call("querySelector", "body")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
app := new(wasmApp)
|
||||
app.params = params
|
||||
app.createContentFunc = createContentFunc
|
||||
app.brige = createWasmBrige()
|
||||
|
||||
app.init()
|
||||
<-app.close
|
||||
}
|
||||
|
||||
func FinishApp() {
|
||||
|
@ -171,31 +183,3 @@ func FinishApp() {
|
|||
func OpenBrowser(url string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
func OpenBrowser(url string) bool {
|
||||
var err error
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
for _, provider := range []string{"xdg-open", "x-www-browser", "www-browser"} {
|
||||
if _, err = exec.LookPath(provider); err == nil {
|
||||
if exec.Command(provider, url).Start(); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "windows":
|
||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
|
||||
case "darwin":
|
||||
err = exec.Command("open", url).Start()
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unsupported platform")
|
||||
}
|
||||
|
||||
return err != nil
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -14,6 +14,47 @@ window.onblur = function(event) {
|
|||
sendMessage( "session-pause{session=" + sessionID +"}" );
|
||||
}
|
||||
|
||||
function sessionInfo() {
|
||||
|
||||
const touch_screen = (('ontouchstart' in document.documentElement) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) ? "1" : "0";
|
||||
var message = "startSession{touch=" + touch_screen
|
||||
|
||||
const style = window.getComputedStyle(document.body);
|
||||
if (style) {
|
||||
var direction = style.getPropertyValue('direction');
|
||||
if (direction) {
|
||||
message += ",direction=" + direction
|
||||
}
|
||||
}
|
||||
|
||||
const lang = window.navigator.language;
|
||||
if (lang) {
|
||||
message += ",language=\"" + lang + "\"";
|
||||
}
|
||||
|
||||
const langs = window.navigator.languages;
|
||||
if (langs) {
|
||||
message += ",languages=\"" + langs + "\"";
|
||||
}
|
||||
|
||||
const userAgent = window.navigator.userAgent
|
||||
if (userAgent) {
|
||||
message += ",user-agent=\"" + userAgent + "\"";
|
||||
}
|
||||
|
||||
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
if (darkThemeMq.matches) {
|
||||
message += ",dark=1";
|
||||
}
|
||||
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
if (pixelRatio) {
|
||||
message += ",pixel-ratio=" + pixelRatio;
|
||||
}
|
||||
|
||||
return message + "}";
|
||||
}
|
||||
|
||||
function getIntAttribute(element, tag) {
|
||||
let value = element.getAttribute(tag);
|
||||
if (value) {
|
||||
|
@ -1276,6 +1317,10 @@ function startDowndload(url, filename) {
|
|||
}
|
||||
}
|
||||
|
||||
function setTitle(title) {
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
function setTitleColor(color) {
|
||||
var metas = document.getElementsByTagName('meta');
|
||||
if (metas) {
|
||||
|
@ -1292,6 +1337,10 @@ function setTitleColor(color) {
|
|||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
}
|
||||
|
||||
function openURL(url) {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
function detailsEvent(element) {
|
||||
sendMessage("details-open{session=" + sessionID + ",id=" + element.id + ",open=" + (element.open ? "1}" : "0}"));
|
||||
}
|
||||
|
@ -1743,3 +1792,7 @@ function getPropertyValue(answerID, elementId, name) {
|
|||
|
||||
sendMessage('answer{answerID=' + answerID + ', value=""}')
|
||||
}
|
||||
|
||||
function appendStyles(styles) {
|
||||
document.querySelector('style').textContent += styles
|
||||
}
|
|
@ -26,44 +26,7 @@ window.onload = function() {
|
|||
};
|
||||
|
||||
function socketOpen() {
|
||||
|
||||
const touch_screen = (('ontouchstart' in document.documentElement) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) ? "1" : "0";
|
||||
var message = "startSession{touch=" + touch_screen
|
||||
|
||||
const style = window.getComputedStyle(document.body);
|
||||
if (style) {
|
||||
var direction = style.getPropertyValue('direction');
|
||||
if (direction) {
|
||||
message += ",direction=" + direction
|
||||
}
|
||||
}
|
||||
|
||||
const lang = window.navigator.language;
|
||||
if (lang) {
|
||||
message += ",language=\"" + lang + "\"";
|
||||
}
|
||||
|
||||
const langs = window.navigator.languages;
|
||||
if (langs) {
|
||||
message += ",languages=\"" + langs + "\"";
|
||||
}
|
||||
|
||||
const userAgent = window.navigator.userAgent
|
||||
if (userAgent) {
|
||||
message += ",user-agent=\"" + userAgent + "\"";
|
||||
}
|
||||
|
||||
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
if (darkThemeMq.matches) {
|
||||
message += ",dark=1";
|
||||
}
|
||||
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
if (pixelRatio) {
|
||||
message += ",pixel-ratio=" + pixelRatio;
|
||||
}
|
||||
|
||||
sendMessage( message + "}" );
|
||||
sendMessage( sessionInfo() );
|
||||
}
|
||||
|
||||
function socketReopen() {
|
||||
|
|
43
app_wasm.js
43
app_wasm.js
|
@ -1,47 +1,8 @@
|
|||
|
||||
|
||||
function initSession() {
|
||||
|
||||
const touch_screen = (('ontouchstart' in document.documentElement) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) ? "1" : "0";
|
||||
var message = "sessionInfo{touch=" + touch_screen
|
||||
|
||||
const style = window.getComputedStyle(document.body);
|
||||
if (style) {
|
||||
var direction = style.getPropertyValue('direction');
|
||||
if (direction) {
|
||||
message += ",direction=" + direction
|
||||
}
|
||||
}
|
||||
|
||||
const lang = window.navigator.language;
|
||||
if (lang) {
|
||||
message += ",language=\"" + lang + "\"";
|
||||
}
|
||||
|
||||
const langs = window.navigator.languages;
|
||||
if (langs) {
|
||||
message += ",languages=\"" + langs + "\"";
|
||||
}
|
||||
|
||||
const userAgent = window.navigator.userAgent
|
||||
if (userAgent) {
|
||||
message += ",user-agent=\"" + userAgent + "\"";
|
||||
}
|
||||
|
||||
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
if (darkThemeMq.matches) {
|
||||
message += ",dark=1";
|
||||
}
|
||||
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
if (pixelRatio) {
|
||||
message += ",pixel-ratio=" + pixelRatio;
|
||||
}
|
||||
|
||||
startSession( message + "}" );
|
||||
function log(s) {
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
|
||||
window.onfocus = function(event) {
|
||||
windowFocus = true
|
||||
sendMessage( "session-resume{session=" + sessionID +"}" );
|
||||
|
|
|
@ -2,7 +2,6 @@ package rui
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -24,7 +23,7 @@ func (session *sessionData) startDownload(file downloadFile) {
|
|||
currentDownloadId++
|
||||
id := strconv.Itoa(currentDownloadId)
|
||||
downloadFiles[id] = file
|
||||
session.runScript(fmt.Sprintf(`startDowndload("%s", "%s")`, id, file.filename))
|
||||
session.runFunc("startDowndload", id, file.filename)
|
||||
}
|
||||
|
||||
func serveDownloadFile(id string, w http.ResponseWriter, r *http.Request) bool {
|
||||
|
|
13
session.go
13
session.go
|
@ -67,7 +67,7 @@ type Session interface {
|
|||
|
||||
// Content returns the SessionContent of session
|
||||
Content() SessionContent
|
||||
setContent(content SessionContent, self Session) bool
|
||||
setContent(content SessionContent) bool
|
||||
|
||||
// SetTitle sets the text of the browser title/tab
|
||||
SetTitle(title string)
|
||||
|
@ -91,6 +91,7 @@ type Session interface {
|
|||
// OpenURL opens the url in the new browser tab
|
||||
OpenURL(url string)
|
||||
|
||||
getCurrentTheme() Theme
|
||||
registerAnimation(props []AnimatedProperty) string
|
||||
|
||||
resolveConstants(value string) (string, bool)
|
||||
|
@ -245,10 +246,10 @@ func (session *sessionData) Content() SessionContent {
|
|||
return session.content
|
||||
}
|
||||
|
||||
func (session *sessionData) setContent(content SessionContent, self Session) bool {
|
||||
func (session *sessionData) setContent(content SessionContent) bool {
|
||||
if content != nil {
|
||||
session.content = content
|
||||
session.rootView = content.CreateRootView(self)
|
||||
session.rootView = content.CreateRootView(session)
|
||||
if session.rootView != nil {
|
||||
session.rootView.setParentID("ruiRootView")
|
||||
return true
|
||||
|
@ -554,11 +555,11 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
|||
|
||||
func (session *sessionData) SetTitle(title string) {
|
||||
title, _ = session.GetString(title)
|
||||
session.runScript(`document.title = "` + title + `";`)
|
||||
session.runFunc("setTitle", title)
|
||||
}
|
||||
|
||||
func (session *sessionData) SetTitleColor(color Color) {
|
||||
session.runScript(`setTitleColor("` + color.cssString() + `");`)
|
||||
session.runFunc("setTitleColor", color.cssString())
|
||||
}
|
||||
|
||||
func (session *sessionData) RemoteAddr() string {
|
||||
|
@ -570,5 +571,5 @@ func (session *sessionData) OpenURL(urlStr string) {
|
|||
ErrorLog(err.Error())
|
||||
return
|
||||
}
|
||||
session.runScript(`window.open("` + urlStr + `", "_blank");`)
|
||||
session.runFunc("openURL", urlStr)
|
||||
}
|
||||
|
|
|
@ -325,15 +325,16 @@ func (session *sessionData) SetLanguage(lang string) {
|
|||
if lang != session.language {
|
||||
session.language = lang
|
||||
|
||||
if session.rootView != nil {
|
||||
if session.rootView != nil && session.brige != nil {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
buffer.WriteString(`document.getElementById('ruiRootView').innerHTML = '`)
|
||||
//buffer.WriteString(`document.getElementById('ruiRootView').innerHTML = '`)
|
||||
viewHTML(session.rootView, buffer)
|
||||
buffer.WriteString("';\nscanElementsSize();")
|
||||
//buffer.WriteString("';\nscanElementsSize();")
|
||||
|
||||
session.runScript(buffer.String())
|
||||
//session.runScript(buffer.String())
|
||||
session.brige.updateInnerHTML("ruiRootView", buffer.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
70
wasmBrige.go
70
wasmBrige.go
|
@ -3,11 +3,10 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type wasmBrige struct {
|
||||
|
@ -18,11 +17,6 @@ type wasmBrige struct {
|
|||
closed bool
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 8096,
|
||||
}
|
||||
|
||||
func createWasmBrige() webBrige {
|
||||
brige := new(wasmBrige)
|
||||
brige.queue = make(chan string, 1000)
|
||||
|
@ -30,23 +24,58 @@ func createWasmBrige() webBrige {
|
|||
brige.answer = make(map[int]chan DataObject)
|
||||
brige.closed = false
|
||||
|
||||
js.Global().Set("sendMessage", js.FuncOf(brige.sendMessage))
|
||||
|
||||
return brige
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) sendMessage(this js.Value, args []js.Value) interface{} {
|
||||
if len(args) > 0 {
|
||||
brige.queue <- args[0].String()
|
||||
func (brige *wasmBrige) startUpdateScript(htmlID string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) finishUpdateScript(htmlID string) {
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) runFunc(funcName string, args ...any) bool {
|
||||
if ProtocolInDebugLog {
|
||||
text := funcName + "("
|
||||
for i, arg := range args {
|
||||
if i > 0 {
|
||||
text += fmt.Sprintf(", `%v`", arg)
|
||||
} else {
|
||||
text += fmt.Sprintf("`%v`", arg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
DebugLog(text + ")")
|
||||
}
|
||||
|
||||
js.Global().Call(funcName, args...)
|
||||
return true
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) updateInnerHTML(htmlID, html string) {
|
||||
brige.runFunc("updateInnerHTML", htmlID, html)
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) appendToInnerHTML(htmlID, html string) {
|
||||
brige.runFunc("appendToInnerHTML", htmlID, html)
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) updateCSSProperty(htmlID, property, value string) {
|
||||
brige.runFunc("updateCSSProperty", htmlID, property, value)
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) updateProperty(htmlID, property string, value any) {
|
||||
brige.runFunc("updateProperty", htmlID, property, value)
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) removeProperty(htmlID, property string) {
|
||||
brige.runFunc("removeProperty", htmlID, property)
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) close() {
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) readMessage() (string, bool) {
|
||||
return <-brige.queue, true
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) writeMessage(script string) bool {
|
||||
|
@ -61,7 +90,8 @@ func (brige *wasmBrige) writeMessage(script string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) runGetterScript(script string) DataObject {
|
||||
/*
|
||||
func (brige *wasmBrige) runGetterScript(script string) DataObject {
|
||||
brige.answerMutex.Lock()
|
||||
answerID := brige.answerID
|
||||
brige.answerID++
|
||||
|
@ -80,6 +110,16 @@ func (brige *wasmBrige) runGetterScript(script string) DataObject {
|
|||
result.SetPropertyValue("text", errorText)
|
||||
delete(brige.answer, answerID)
|
||||
return result
|
||||
}
|
||||
*/
|
||||
|
||||
func (brige *wasmBrige) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
||||
// TODO
|
||||
return TextMetrics{}
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) htmlPropertyValue(htmlID, name string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (brige *wasmBrige) answerReceived(answer DataObject) {
|
||||
|
|
|
@ -175,7 +175,6 @@ func (brige *wsBrige) updateCSSProperty(htmlID, property, value string) {
|
|||
} else {
|
||||
brige.runFunc("updateCSSProperty", htmlID, property, value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (brige *wsBrige) updateProperty(htmlID, property string, value any) {
|
||||
|
|
Loading…
Reference in New Issue