mirror of https://github.com/anoshenko/rui.git
Added ClientSession interface
* Added ClientSession interface * Added ClientSession method to Session interface * Removed ClientItem, SetClientItem, RemoveClientItem, and RemoveAllClientItems methods from Session interface
This commit is contained in:
parent
7b442dea72
commit
85e244babf
|
|
@ -3,7 +3,9 @@
|
||||||
* Removed "style-disabled" property and GetDisabledStyle function
|
* Removed "style-disabled" property and GetDisabledStyle function
|
||||||
* Added GoogleFonts field to AppParams
|
* Added GoogleFonts field to AppParams
|
||||||
* Added functions: GetWhiteSpace, GetWordBreak, ScrollIntoViewIfNeeded
|
* Added functions: GetWhiteSpace, GetWordBreak, ScrollIntoViewIfNeeded
|
||||||
* Added Popups, PopupDefault, PopupDefaultsSeq, and SetPopupDefaults methods to Session interface
|
* Added ClientSession interface
|
||||||
|
* Added ClientSession, Popups, PopupDefault, PopupDefaultsSeq, and SetPopupDefaults methods to Session interface
|
||||||
|
* Removed ClientItem, SetClientItem, RemoveClientItem, and RemoveAllClientItems methods from Session interface
|
||||||
* Added DismissWithoutAnimation add SetHotKey methods to Popup interface
|
* Added DismissWithoutAnimation add SetHotKey methods to Popup interface
|
||||||
* Added "outside-color" add "outside-filter" properties to Popup interface
|
* Added "outside-color" add "outside-filter" properties to Popup interface
|
||||||
* Added ViewSeq add ViewCount methods to ParentView interface
|
* Added ViewSeq add ViewCount methods to ParentView interface
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ function sessionInfo() {
|
||||||
message += ",pixel-ratio=" + pixelRatio;
|
message += ",pixel-ratio=" + pixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (localStorage.length > 0) {
|
if (localStorage.length > 0) {
|
||||||
message += ",storage="
|
message += ",storage="
|
||||||
lead = "_{"
|
lead = "_{"
|
||||||
|
|
@ -73,6 +74,7 @@ function sessionInfo() {
|
||||||
}
|
}
|
||||||
message += "}"
|
message += "}"
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return message + "}";
|
return message + "}";
|
||||||
}
|
}
|
||||||
|
|
@ -1984,6 +1986,38 @@ function getCanvasContext(elementId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function localStorageGet(request, keys) {
|
||||||
|
const key_set = keys.split(",");
|
||||||
|
var result = "";
|
||||||
|
for (const key of key_set) {
|
||||||
|
result += key;
|
||||||
|
result += ":";
|
||||||
|
try {
|
||||||
|
let value = localStorage.getItem(key);
|
||||||
|
if (value) {
|
||||||
|
result += value;
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
result += ";";
|
||||||
|
}
|
||||||
|
sendMessage("storageValues{session=" + sessionID + ", request=" + request + ", values=`" + result + "`}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function localStorageGetAll(request) {
|
||||||
|
var result = "";
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
let key = localStorage.key(i);
|
||||||
|
let value = localStorage.getItem(key);
|
||||||
|
if (value) {
|
||||||
|
result += key;
|
||||||
|
result += ":";
|
||||||
|
result += value;
|
||||||
|
result += ";";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendMessage("storageValues{session=" + sessionID + ", request=" + request + ", values=`" + result + "`}")
|
||||||
|
}
|
||||||
|
|
||||||
function localStorageSet(key, value) {
|
function localStorageSet(key, value) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(key, value);
|
localStorage.setItem(key, value);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientStorage is an interface for accessing client-side key-value storage.
|
||||||
|
type ClientStorage interface {
|
||||||
|
|
||||||
|
// Request performs an asynchronous request to obtain key-value pairs from client-side storage.
|
||||||
|
//
|
||||||
|
// The first argument specifies the function that is called for each key-value pair
|
||||||
|
// (if the pair is not in storage, then the function is called with an empty string as its value).
|
||||||
|
//
|
||||||
|
// The second argument specifies the set of keys to request.
|
||||||
|
// If no key is specified, then a query is performed for all possible key-value pairs.
|
||||||
|
Request(result func(key, value string), key ...string)
|
||||||
|
|
||||||
|
// Get returns a value by key from the client-side storage.
|
||||||
|
//
|
||||||
|
// If the key-value pair is not in the client-side storage, then the function returns an empty string.
|
||||||
|
Get(key string) string
|
||||||
|
|
||||||
|
// Set stores a key-value pair in the client-side storage.
|
||||||
|
//
|
||||||
|
// An empty string as a value removes the key-value pair.
|
||||||
|
Set(key, value string)
|
||||||
|
|
||||||
|
// RemoveAll removes all key-value pair from the client-side storage
|
||||||
|
RemoveAll()
|
||||||
|
|
||||||
|
handleEvent(command string, data DataObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientStorageData struct {
|
||||||
|
bridge bridge
|
||||||
|
getResult map[int]func(string, string)
|
||||||
|
lastRequest int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *sessionData) ClientStorage() ClientStorage {
|
||||||
|
if session.clientStorage == nil {
|
||||||
|
storage := new(clientStorageData)
|
||||||
|
storage.bridge = session.bridge
|
||||||
|
session.clientStorage = storage
|
||||||
|
}
|
||||||
|
return session.clientStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeClientStorageText(text string) string {
|
||||||
|
return base64.URLEncoding.EncodeToString([]byte(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeClientStorageText(text string) string {
|
||||||
|
result, _ := base64.URLEncoding.DecodeString(text)
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storage *clientStorageData) Get(key string) string {
|
||||||
|
result := make(chan string)
|
||||||
|
defer close(result)
|
||||||
|
|
||||||
|
storage.Request(func(key, value string) {
|
||||||
|
result <- value
|
||||||
|
}, key)
|
||||||
|
|
||||||
|
return <-result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storage *clientStorageData) Request(result func(key, value string), key ...string) {
|
||||||
|
if result == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.lastRequest++
|
||||||
|
request := storage.lastRequest
|
||||||
|
storage.getResult[request] = result
|
||||||
|
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
for _, k := range key {
|
||||||
|
if k != "" {
|
||||||
|
if buffer.Len() > 0 {
|
||||||
|
buffer.WriteRune(',')
|
||||||
|
}
|
||||||
|
buffer.WriteString(encodeClientStorageText(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
storage.bridge.callFunc("localStorageGetAll", request)
|
||||||
|
} else {
|
||||||
|
storage.bridge.callFunc("localStorageGet", request, buffer.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storage *clientStorageData) Set(key, value string) {
|
||||||
|
key = encodeClientStorageText(key)
|
||||||
|
if value != "" {
|
||||||
|
storage.bridge.callFunc("localStorageSet", key, encodeClientStorageText(value))
|
||||||
|
} else {
|
||||||
|
storage.bridge.callFunc("localStorageRemove", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storage *clientStorageData) RemoveAll() {
|
||||||
|
storage.bridge.callFunc("localStorageClear")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
||||||
|
request := 0
|
||||||
|
if text, ok := data.PropertyValue("request"); ok {
|
||||||
|
var err error
|
||||||
|
if request, err = strconv.Atoi(text); err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog("'request' property not found (command: " + command + ")")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case "storageError":
|
||||||
|
if text, ok := data.PropertyValue("error"); ok {
|
||||||
|
ErrorLog(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
//case "storageSuccess":
|
||||||
|
|
||||||
|
case "storageValues":
|
||||||
|
fn, ok := storage.getResult[request]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(storage.getResult, request)
|
||||||
|
|
||||||
|
text, ok := data.PropertyValue("error")
|
||||||
|
if !ok {
|
||||||
|
ErrorLog("'values' property not found (command: storageValues)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for pair := range strings.SplitSeq(text, ";") {
|
||||||
|
if data := strings.Split(pair, ":"); len(data) == 2 {
|
||||||
|
key := decodeClientStorageText(data[0])
|
||||||
|
value := decodeClientStorageText(data[1])
|
||||||
|
fn(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
session.go
52
session.go
|
|
@ -135,17 +135,8 @@ type Session interface {
|
||||||
// OpenURL opens the url in the new browser tab
|
// OpenURL opens the url in the new browser tab
|
||||||
OpenURL(url string)
|
OpenURL(url string)
|
||||||
|
|
||||||
// ClientItem reads value by key from the client-side storage
|
// ClientStorage returns an interface for accessing client-side key-value storage.
|
||||||
ClientItem(key string) (string, bool)
|
ClientStorage() ClientStorage
|
||||||
|
|
||||||
// SetClientItem stores a key-value pair in the client-side storage
|
|
||||||
SetClientItem(key, value string)
|
|
||||||
|
|
||||||
// RemoveClientItem removes a key-value pair in the client-side storage
|
|
||||||
RemoveClientItem(key string)
|
|
||||||
|
|
||||||
// RemoveAllClientItems removes all key-value pair from the client-side storage
|
|
||||||
RemoveAllClientItems()
|
|
||||||
|
|
||||||
// SetHotKey sets the function that will be called when the given hotkey is pressed.
|
// SetHotKey sets the function that will be called when the given hotkey is pressed.
|
||||||
// Invoke SetHotKey(..., ..., nil) for remove hotkey function.
|
// Invoke SetHotKey(..., ..., nil) for remove hotkey function.
|
||||||
|
|
@ -248,12 +239,12 @@ type sessionData struct {
|
||||||
animationCounter int
|
animationCounter int
|
||||||
animationCSS string
|
animationCSS string
|
||||||
updateScripts map[string]*strings.Builder
|
updateScripts map[string]*strings.Builder
|
||||||
clientStorage map[string]string
|
|
||||||
hotkeys map[string]func(Session)
|
hotkeys map[string]func(Session)
|
||||||
timers map[int]func(Session)
|
timers map[int]func(Session)
|
||||||
nextTimerID int
|
nextTimerID int
|
||||||
pauseTime int64
|
pauseTime int64
|
||||||
popupDefaults Params
|
popupDefaults Params
|
||||||
|
clientStorage ClientStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(app Application, id int, customTheme string, params DataObject) Session {
|
func newSession(app Application, id int, customTheme string, params DataObject) Session {
|
||||||
|
|
@ -270,7 +261,6 @@ func newSession(app Application, id int, customTheme string, params DataObject)
|
||||||
session.animationCounter = 0
|
session.animationCounter = 0
|
||||||
session.animationCSS = ""
|
session.animationCSS = ""
|
||||||
session.updateScripts = map[string]*strings.Builder{}
|
session.updateScripts = map[string]*strings.Builder{}
|
||||||
session.clientStorage = map[string]string{}
|
|
||||||
session.hotkeys = map[string]func(Session){}
|
session.hotkeys = map[string]func(Session){}
|
||||||
session.timers = map[int]func(Session){}
|
session.timers = map[int]func(Session){}
|
||||||
session.nextTimerID = 1
|
session.nextTimerID = 1
|
||||||
|
|
@ -781,16 +771,6 @@ func (session *sessionData) handleSessionInfo(params DataObject) {
|
||||||
session.pixelRatio = f
|
session.pixelRatio = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if node := params.PropertyByTag("storage"); node != nil && node.Type() == ObjectNode {
|
|
||||||
if obj := node.Object(); obj != nil {
|
|
||||||
for element := range obj.Properties() {
|
|
||||||
if element.Type() == TextNode {
|
|
||||||
session.clientStorage[element.Tag()] = element.Text()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleEvent(command string, data DataObject) {
|
func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
|
|
@ -826,9 +806,9 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
case "sessionInfo":
|
case "sessionInfo":
|
||||||
session.handleSessionInfo(data)
|
session.handleSessionInfo(data)
|
||||||
|
|
||||||
case "storageError":
|
case "storageError", "storageSuccess", "storageValues":
|
||||||
if text, ok := data.PropertyValue("error"); ok {
|
if session.clientStorage != nil {
|
||||||
ErrorLog(text)
|
session.clientStorage.handleEvent(command, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -932,26 +912,6 @@ func (session *sessionData) OpenURL(urlStr string) {
|
||||||
session.callFunc("openURL", urlStr)
|
session.callFunc("openURL", urlStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) ClientItem(key string) (string, bool) {
|
|
||||||
value, ok := session.clientStorage[key]
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session *sessionData) SetClientItem(key, value string) {
|
|
||||||
session.clientStorage[key] = value
|
|
||||||
session.bridge.callFunc("localStorageSet", key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session *sessionData) RemoveClientItem(key string) {
|
|
||||||
delete(session.clientStorage, key)
|
|
||||||
session.bridge.callFunc("localStorageRemove", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session *sessionData) RemoveAllClientItems() {
|
|
||||||
session.clientStorage = map[string]string{}
|
|
||||||
session.bridge.callFunc("localStorageClear")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session *sessionData) addToEventsQueue(data DataObject) {
|
func (session *sessionData) addToEventsQueue(data DataObject) {
|
||||||
session.events <- data
|
session.events <- data
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue