From befb2a7484bc06a09ff0f4fbf85c94eef407a1df Mon Sep 17 00:00:00 2001 From: anoshenko Date: Mon, 22 Apr 2024 13:09:35 +0300 Subject: [PATCH] Added StartTimer and StopTimer to Session --- CHANGELOG.md | 9 +++++++++ app_post.js | 23 +++++++++++------------ app_scripts.js | 22 ++++++++++++++++++++++ session.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ webBridge.go | 12 ++++-------- 5 files changed, 92 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f83066..854b67e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# v0.14.0 +* Added the ability to work without creating a WebSocket. Added NoSocket property of AppParams. +* Added the ability to run a timer on the client side. Added StartTimer and StopTimer methods to Session interface. +* Bug fixing + +# v0.13.x +* Added NewHandler function +* Bug fixing + # v0.13.0 * Added SetHotKey function to Session interface diff --git a/app_post.js b/app_post.js index e557c55..be60262 100644 --- a/app_post.js +++ b/app_post.js @@ -1,16 +1,15 @@ -function sendMessage(message) { - let xhr = new XMLHttpRequest(); - xhr.open('POST', '/', true); - xhr.onreadystatechange = function() { - const script = this.responseText - if (script != "") { - window.eval(script) - //sendMessage("nop{session=" + sessionID +"}") - } - - } - xhr.send(message); +async function sendMessage(message) { + const response = await fetch('/', { + method : 'POST', + body : message, + "Content-Type" : "text/plain", + }); + + const text = await response.text(); + if (text != "") { + window.eval(text) + } } window.onload = function() { diff --git a/app_scripts.js b/app_scripts.js index 222a40e..856ffce 100644 --- a/app_scripts.js +++ b/app_scripts.js @@ -1861,6 +1861,28 @@ function imageError(element, event) { sendMessage(message); } +let timers = new Map(); + +function startTimer(ms, timerID) { + let data = { + id: setInterval(timerFunc, ms, timerID), + ms: ms, + }; + timers.set(timerID, data); +} + +function timerFunc(timerID) { + sendMessage("timer{session=" + sessionID + ",timerID=" + timerID + "}"); +} + +function stopTimer(timerID) { + let timer = timers.get(timerID); + if (timer) { + clearInterval(timer.id); + timers.delete(timerID); + } +} + function canvasTextMetrics(answerID, elementId, font, text) { let w = 0; let ascent = 0; diff --git a/session.go b/session.go index 31e5930..0b1505f 100644 --- a/session.go +++ b/session.go @@ -110,6 +110,14 @@ type Session interface { // Invoke SetHotKey(..., ..., nil) for remove hotkey function. SetHotKey(keyCode KeyCode, controlKeys ControlKeyMask, fn func(Session)) + // StartTimer starts a timer on the client side. + // The first argument specifies the timer period in milliseconds. + // The second argument specifies a function that will be called on each timer event. + // The result is the id of the timer, which is used to stop the timer + StartTimer(ms int, timerFunc func(Session)) int + // StopTimer the timer with the given id + StopTimer(timerID int) + getCurrentTheme() Theme registerAnimation(props []AnimatedProperty) string @@ -197,6 +205,8 @@ type sessionData struct { updateScripts map[string]*strings.Builder clientStorage map[string]string hotkeys map[string]func(Session) + timers map[int]func(Session) + nextTimerID int } func newSession(app Application, id int, customTheme string, params DataObject) Session { @@ -215,6 +225,8 @@ func newSession(app Application, id int, customTheme string, params DataObject) session.updateScripts = map[string]*strings.Builder{} session.clientStorage = map[string]string{} session.hotkeys = map[string]func(Session){} + session.timers = map[int]func(Session){} + session.nextTimerID = 1 if customTheme != "" { if theme, ok := CreateThemeFromText(customTheme); ok { @@ -664,6 +676,22 @@ func (session *sessionData) handleEvent(command string, data DataObject) { case "session-resume": session.onResume() + case "timer": + if text, ok := data.PropertyValue("timerID"); ok { + timerID, err := strconv.Atoi(text) + if err == nil { + if fn, ok := session.timers[timerID]; ok { + fn(session) + } else { + ErrorLog(`Timer (id = ` + text + `) not exists`) + } + } else { + ErrorLog(err.Error()) + } + } else { + ErrorLog(`"timerID" property not found`) + } + case "root-size": session.handleRootSize(data) @@ -797,3 +825,21 @@ func (session *sessionData) RemoveAllClientItems() { func (session *sessionData) addToEventsQueue(data DataObject) { session.events <- data } + +func (session *sessionData) StartTimer(ms int, timerFunc func(Session)) int { + timerID := 0 + if session.bridge != nil { + timerID = session.nextTimerID + session.nextTimerID++ + session.timers[timerID] = timerFunc + session.bridge.callFunc("startTimer", ms, timerID) + } + return timerID +} + +func (session *sessionData) StopTimer(timerID int) { + if session.bridge != nil { + session.bridge.callFunc("stopTimer", timerID) + delete(session.timers, timerID) + } +} diff --git a/webBridge.go b/webBridge.go index 9ec2ea6..004eeea 100644 --- a/webBridge.go +++ b/webBridge.go @@ -397,7 +397,7 @@ func (bridge *webBridge) canvasFinish() { bridge.writeMessage(bridge.canvasBuffer.String()) } -func (bridge *webBridge) removeValue(funcName, htmlID string, args ...string) (DataObject, bool) { +func (bridge *webBridge) remoteValue(funcName string, args ...any) (DataObject, bool) { bridge.answerMutex.Lock() answerID := bridge.answerID bridge.answerID++ @@ -406,11 +406,7 @@ func (bridge *webBridge) removeValue(funcName, htmlID string, args ...string) (D answer := make(chan DataObject) bridge.answer[answerID] = answer - funcArgs := []any{answerID, htmlID} - for _, arg := range args { - funcArgs = append(funcArgs, arg) - } - + funcArgs := append([]any{answerID}, args...) var result DataObject = nil ok := bridge.callFuncImmediately(funcName, funcArgs...) if ok { @@ -424,14 +420,14 @@ func (bridge *webBridge) removeValue(funcName, htmlID string, args ...string) (D func (bridge *webBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics { result := TextMetrics{} - if data, ok := bridge.removeValue("canvasTextMetrics", htmlID, font, text); ok { + if data, ok := bridge.remoteValue("canvasTextMetrics", htmlID, font, text); ok { result.Width = dataFloatProperty(data, "width") } return result } func (bridge *webBridge) htmlPropertyValue(htmlID, name string) string { - if data, ok := bridge.removeValue("getPropertyValue", htmlID, name); ok { + if data, ok := bridge.remoteValue("getPropertyValue", htmlID, name); ok { if value, ok := data.PropertyValue("value"); ok { return value }