fix: components not using parent page patchShan; fix: chat example nil pointer error when sync outside action
This commit is contained in:
25
context.go
25
context.go
@@ -189,7 +189,7 @@ func (c *Context) injectSignals(sigs map[string]any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) getSSE() chan patch {
|
func (c *Context) getPatchChan() chan patch {
|
||||||
// components use parent page sse stream
|
// components use parent page sse stream
|
||||||
var patchChan chan patch
|
var patchChan chan patch
|
||||||
if c.isComponent() {
|
if c.isComponent() {
|
||||||
@@ -220,12 +220,13 @@ func (c *Context) prepareSignalsForPatch() map[string]any {
|
|||||||
// Sync pushes the current view state and signal changes to the browser immediately
|
// Sync pushes the current view state and signal changes to the browser immediately
|
||||||
// over the live SSE event stream.
|
// over the live SSE event stream.
|
||||||
func (c *Context) Sync() {
|
func (c *Context) Sync() {
|
||||||
|
patchChan := c.getPatchChan()
|
||||||
elemsPatch := bytes.NewBuffer(make([]byte, 0))
|
elemsPatch := bytes.NewBuffer(make([]byte, 0))
|
||||||
if err := c.view().Render(elemsPatch); err != nil {
|
if err := c.view().Render(elemsPatch); err != nil {
|
||||||
c.app.logErr(c, "sync view failed: %v", err)
|
c.app.logErr(c, "sync view failed: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.patchChan <- patch{patchTypeElements, elemsPatch.String()}
|
patchChan <- patch{patchTypeElements, elemsPatch.String()}
|
||||||
|
|
||||||
c.mutex.RLock()
|
c.mutex.RLock()
|
||||||
defer c.mutex.RUnlock()
|
defer c.mutex.RUnlock()
|
||||||
@@ -233,7 +234,7 @@ func (c *Context) Sync() {
|
|||||||
|
|
||||||
if len(updatedSigs) != 0 {
|
if len(updatedSigs) != 0 {
|
||||||
outgoingSigs, _ := json.Marshal(updatedSigs)
|
outgoingSigs, _ := json.Marshal(updatedSigs)
|
||||||
c.patchChan <- patch{patchTypeSignals, string(outgoingSigs)}
|
patchChan <- patch{patchTypeSignals, string(outgoingSigs)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,11 +256,7 @@ func (c *Context) Sync() {
|
|||||||
// Then, the merge will only occur if the ID of the top level element in the patch
|
// Then, the merge will only occur if the ID of the top level element in the patch
|
||||||
// matches 'my-element'.
|
// matches 'my-element'.
|
||||||
func (c *Context) SyncElements(elem h.H) {
|
func (c *Context) SyncElements(elem h.H) {
|
||||||
sse := c.getSSE()
|
patchChan := c.getPatchChan()
|
||||||
if sse == nil {
|
|
||||||
c.app.logWarn(c, "elements out of sync: no sse stream")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.view == nil {
|
if c.view == nil {
|
||||||
c.app.logErr(c, "sync element failed: viewfn is nil")
|
c.app.logErr(c, "sync element failed: viewfn is nil")
|
||||||
return
|
return
|
||||||
@@ -270,29 +267,29 @@ func (c *Context) SyncElements(elem h.H) {
|
|||||||
}
|
}
|
||||||
b := bytes.NewBuffer(make([]byte, 0))
|
b := bytes.NewBuffer(make([]byte, 0))
|
||||||
_ = elem.Render(b)
|
_ = elem.Render(b)
|
||||||
c.patchChan <- patch{patchTypeElements, b.String()}
|
patchChan <- patch{patchTypeElements, b.String()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncSignals pushes the current signal changes to the browser immediately
|
// SyncSignals pushes the current signal changes to the browser immediately
|
||||||
// over the live SSE event stream.
|
// over the live SSE event stream.
|
||||||
func (c *Context) SyncSignals() {
|
func (c *Context) SyncSignals() {
|
||||||
|
patchChan := c.getPatchChan()
|
||||||
c.mutex.RLock()
|
c.mutex.RLock()
|
||||||
updatedSigs := c.prepareSignalsForPatch()
|
updatedSigs := c.prepareSignalsForPatch()
|
||||||
defer c.mutex.RUnlock()
|
defer c.mutex.RUnlock()
|
||||||
|
|
||||||
if len(updatedSigs) != 0 {
|
if len(updatedSigs) != 0 {
|
||||||
outgoingSignals, _ := json.Marshal(updatedSigs)
|
outgoingSignals, _ := json.Marshal(updatedSigs)
|
||||||
c.patchChan <- patch{patchTypeSignals, string(outgoingSignals)}
|
patchChan <- patch{patchTypeSignals, string(outgoingSignals)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) ExecScript(s string) {
|
func (c *Context) ExecScript(s string) {
|
||||||
sse := c.getSSE()
|
if s == "" {
|
||||||
if sse == nil {
|
|
||||||
c.app.logWarn(c, "script out of sync: no sse stream")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.patchChan <- patch{patchTypeScript, s}
|
patchChan := c.getPatchChan()
|
||||||
|
patchChan <- patch{patchTypeScript, s}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext(id string, route string, app *V) *Context {
|
func newContext(id string, route string, app *V) *Context {
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ func main() {
|
|||||||
newRoom.Join(&UserAndSync[Chat, UserInfo]{user: ¤tUser, sync: c})
|
newRoom.Join(&UserAndSync[Chat, UserInfo]{user: ¤tUser, sync: c})
|
||||||
currentRoom = newRoom
|
currentRoom = newRoom
|
||||||
roomNameString = newRoom.Name
|
roomNameString = newRoom.Name
|
||||||
c.Sync()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switchRoomAction := c.Action(func() {
|
switchRoomAction := c.Action(func() {
|
||||||
switchRoom()
|
switchRoom()
|
||||||
|
c.Sync()
|
||||||
})
|
})
|
||||||
|
|
||||||
switchRoom()
|
switchRoom()
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
v := via.New()
|
v := via.New()
|
||||||
|
|
||||||
|
v.Config(via.Options{
|
||||||
|
LogLvl: via.LogLevelDebug,
|
||||||
|
DevMode: true,
|
||||||
|
})
|
||||||
|
|
||||||
v.AppendToHead(
|
v.AppendToHead(
|
||||||
h.Link(h.Rel("stylesheet"), h.Href("https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css")),
|
h.Link(h.Rel("stylesheet"), h.Href("https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css")),
|
||||||
h.Script(h.Src("https://unpkg.com/echarts@6.0.0/dist/echarts.min.js")),
|
h.Script(h.Src("https://unpkg.com/echarts@6.0.0/dist/echarts.min.js")),
|
||||||
@@ -35,7 +40,7 @@ func chartCompFn(c *via.Context) {
|
|||||||
data := make([]float64, 1000)
|
data := make([]float64, 1000)
|
||||||
labels := make([]string, 1000)
|
labels := make([]string, 1000)
|
||||||
|
|
||||||
isLive := false
|
isLive := true
|
||||||
refreshRate := c.Signal(1)
|
refreshRate := c.Signal(1)
|
||||||
tkr := time.NewTicker(1000 * time.Millisecond)
|
tkr := time.NewTicker(1000 * time.Millisecond)
|
||||||
|
|
||||||
@@ -71,7 +76,7 @@ func chartCompFn(c *via.Context) {
|
|||||||
return h.Div(
|
return h.Div(
|
||||||
h.Div(h.ID("chart"), h.Style("width:100%;height:400px;"),
|
h.Div(h.ID("chart"), h.Style("width:100%;height:400px;"),
|
||||||
h.Script(h.Raw(`
|
h.Script(h.Raw(`
|
||||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
var myChart = echarts.init(document.getElementById('chart'), prefersDark.matches ? 'dark' : 'light');
|
var myChart = echarts.init(document.getElementById('chart'), prefersDark.matches ? 'dark' : 'light');
|
||||||
var option = {
|
var option = {
|
||||||
backgroundColor: prefersDark.matches ? 'transparent' : '#ffffff',
|
backgroundColor: prefersDark.matches ? 'transparent' : '#ffffff',
|
||||||
|
|||||||
1
via.go
1
via.go
@@ -153,6 +153,7 @@ func (v *V) Page(route string, initContextFn func(c *Context)) {
|
|||||||
bottomBodyElements = append(bottomBodyElements, v.documentFootIncludes...)
|
bottomBodyElements = append(bottomBodyElements, v.documentFootIncludes...)
|
||||||
if v.cfg.DevMode {
|
if v.cfg.DevMode {
|
||||||
bottomBodyElements = append(bottomBodyElements, h.Script(h.Type("module"), h.Src("https://cdn.jsdelivr.net/gh/dataSPA/dataSPA-inspector@latest/dataspa-inspector.bundled.js")))
|
bottomBodyElements = append(bottomBodyElements, h.Script(h.Type("module"), h.Src("https://cdn.jsdelivr.net/gh/dataSPA/dataSPA-inspector@latest/dataspa-inspector.bundled.js")))
|
||||||
|
bottomBodyElements = append(bottomBodyElements, h.Raw("<dataspa-inspector/>"))
|
||||||
}
|
}
|
||||||
view := h.HTML5(h.HTML5Props{
|
view := h.HTML5(h.HTML5Props{
|
||||||
Title: v.cfg.DocumentTitle,
|
Title: v.cfg.DocumentTitle,
|
||||||
|
|||||||
Reference in New Issue
Block a user