diff --git a/clickhandler.go b/clickhandler.go index e35ac04..d6b04a5 100644 --- a/clickhandler.go +++ b/clickhandler.go @@ -3,14 +3,14 @@ package jaws import "github.com/linkdata/jaws/what" type ClickHandler interface { - JawsClick(e *Element, name string) (err error) + JawsClick(e *Element, name string) (stop bool, err error) } type clickHandlerWapper struct{ ClickHandler } -func (chw clickHandlerWapper) JawsEvent(e *Element, w what.What, v string) (err error) { +func (chw clickHandlerWapper) JawsEvent(e *Element, w what.What, v string) (stop bool, err error) { if w == what.Click { - err = chw.JawsClick(e, v) + return chw.JawsClick(e, v) } return } diff --git a/eventhandler.go b/eventhandler.go index cc7f24b..2fcccdd 100644 --- a/eventhandler.go +++ b/eventhandler.go @@ -3,43 +3,41 @@ package jaws import "github.com/linkdata/jaws/what" type EventHandler interface { - JawsEvent(e *Element, wht what.What, val string) (err error) + JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) } // EventFn is the signature of a event handling function to be called when JaWS receives // an event message from the Javascript via the WebSocket connection. -type EventFn = func(e *Element, wht what.What, val string) error +type EventFn = func(e *Element, wht what.What, val string) (stop bool, err error) type eventFnWrapper struct{ EventFn } -func (ehf eventFnWrapper) JawsEvent(e *Element, w what.What, v string) error { +func (ehf eventFnWrapper) JawsEvent(e *Element, w what.What, v string) (stop bool, err error) { return ehf.EventFn(e, w, v) } var _ EventFn = eventFnWrapper{}.JawsEvent // statically ensure JawsEvent and EventFn are compatible -func callEventHandler(obj any, e *Element, wht what.What, val string) error { +func callEventHandler(obj any, e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Click { if h, ok := obj.(ClickHandler); ok { - if err := h.JawsClick(e, val); err != nil { - return err + if stop, err = h.JawsClick(e, val); stop || err != nil { + return } } } if h, ok := obj.(EventHandler); ok { - if err := h.JawsEvent(e, wht, val); err != nil { - return err - } + return h.JawsEvent(e, wht, val) } - return nil + return } func callAllEventHandlers(e *Element, wht what.What, val string) error { - if err := callEventHandler(e.ui, e, wht, val); err != nil { + if stop, err := callEventHandler(e.ui, e, wht, val); stop || err != nil { return err } for _, h := range e.handlers { - if err := h.JawsEvent(e, wht, val); err != nil { + if stop, err := h.JawsEvent(e, wht, val); stop || err != nil { return err } } diff --git a/request_test.go b/request_test.go index 640f02b..1d09f00 100644 --- a/request_test.go +++ b/request_test.go @@ -210,11 +210,11 @@ func TestRequest_OutboundRespectsJawsClosed(t *testing.T) { jw := rq.jw var callCount int32 tag := Tag("foo") - rq.Register(tag, func(e *Element, evt what.What, val string) error { + rq.Register(tag, func(e *Element, evt what.What, val string) (bool, error) { atomic.AddInt32(&callCount, 1) is.Equal(1, jw.RequestCount()) jw.Close() - return errors.New(val) + return false, errors.New(val) }) fillWsCh(rq.outCh) jw.Broadcast(Message{Dest: Tag("foo"), What: what.Hook, Data: "bar"}) @@ -233,10 +233,10 @@ func TestRequest_OutboundRespectsContextDone(t *testing.T) { defer rq.Close() var callCount int32 tag := Tag("foo") - rq.Register(tag, func(e *Element, evt what.What, val string) error { + rq.Register(tag, func(e *Element, evt what.What, val string) (bool, error) { atomic.AddInt32(&callCount, 1) rq.cancel() - return errors.New(val) + return false, errors.New(val) }) fillWsCh(rq.outCh) rq.jw.Broadcast(Message{Dest: Tag("foo"), What: what.Hook, Data: "bar"}) @@ -278,16 +278,16 @@ func TestRequest_Trigger(t *testing.T) { defer rq.Close() gotFooCall := make(chan struct{}) gotEndCall := make(chan struct{}) - rq.Register("foo", func(e *Element, evt what.What, val string) error { + rq.Register("foo", func(e *Element, evt what.What, val string) (bool, error) { defer close(gotFooCall) - return nil + return false, nil }) - rq.Register(("err"), func(e *Element, evt what.What, val string) error { - return errors.New(val) + rq.Register(("err"), func(e *Element, evt what.What, val string) (bool, error) { + return false, errors.New(val) }) - rq.Register(("end"), func(e *Element, evt what.What, val string) error { + rq.Register(("end"), func(e *Element, evt what.What, val string) (bool, error) { defer close(gotEndCall) - return nil + return false, nil }) // broadcasts from ourselves should not invoke fn @@ -337,7 +337,7 @@ func TestRequest_EventFnQueue(t *testing.T) { firstDoneCh := make(chan struct{}) var sleepDone int32 var callCount int32 - rq.Register(("sleep"), func(e *Element, evt what.What, val string) error { + rq.Register(("sleep"), func(e *Element, evt what.What, val string) (bool, error) { count := int(atomic.AddInt32(&callCount, 1)) if val != strconv.Itoa(count) { t.Logf("val=%s, count=%d, cap=%d", val, count, cap(rq.outCh)) @@ -349,7 +349,7 @@ func TestRequest_EventFnQueue(t *testing.T) { for atomic.LoadInt32(&sleepDone) == 0 { time.Sleep(time.Millisecond) } - return nil + return false, nil }) for i := 0; i < cap(rq.outCh); i++ { @@ -389,9 +389,9 @@ func TestRequest_EventFnQueueOverflowPanicsWithNoLogger(t *testing.T) { var wait int32 - rq.Register(("bomb"), func(e *Element, evt what.What, val string) error { + rq.Register(("bomb"), func(e *Element, evt what.What, val string) (bool, error) { time.Sleep(time.Millisecond * time.Duration(atomic.AddInt32(&wait, 1))) - return nil + return false, nil }) rq.expectPanic = true @@ -418,7 +418,7 @@ func TestRequest_IgnoresIncomingMsgsDuringShutdown(t *testing.T) { var spewState int32 var callCount int32 - rq.Register(("spew"), func(e *Element, evt what.What, val string) error { + rq.Register(("spew"), func(e *Element, evt what.What, val string) (bool, error) { atomic.AddInt32(&callCount, 1) if len(rq.outCh) < cap(rq.outCh) { rq.jw.Broadcast(Message{Dest: Tag("spew"), What: what.Input}) @@ -428,7 +428,7 @@ func TestRequest_IgnoresIncomingMsgsDuringShutdown(t *testing.T) { time.Sleep(time.Millisecond) } } - return errors.New("chunks") + return false, errors.New("chunks") }) rq.Register(Tag("foo")) diff --git a/session_test.go b/session_test.go index 9ca5aba..efac32b 100644 --- a/session_test.go +++ b/session_test.go @@ -176,7 +176,7 @@ func TestSession_Delete(t *testing.T) { rq2 := ts.jw.NewRequest(hr2) is.Equal(ts.sess, rq2.Session()) - ts.rq.Register("byebye", func(e *Element, evt what.What, val string) error { + ts.rq.Register("byebye", func(e *Element, evt what.What, val string) (bool, error) { sess2 := ts.jw.GetSession(e.Request.Initial) is.Equal(ts.sess, sess2) cookie2 := sess2.Close() @@ -185,7 +185,7 @@ func TestSession_Delete(t *testing.T) { is.True(cookie2.Expires.IsZero()) is.Equal(cookie1.Name, cookie2.Name) is.Equal(cookie1.Value, cookie2.Value) - return nil + return false, nil }) conn, resp, err := websocket.Dial(ts.ctx, ts.Url(), nil) diff --git a/template.go b/template.go index 16846b5..316b328 100644 --- a/template.go +++ b/template.go @@ -50,6 +50,6 @@ func (t Template) JawsUpdate(e *Element) { var _ EventHandler = (*Template)(nil) // statically ensure interface is defined -func (t Template) JawsEvent(e *Element, wht what.What, val string) error { +func (t Template) JawsEvent(e *Element, wht what.What, val string) (bool, error) { return callEventHandler(t.Dot, e, wht, val) } diff --git a/uihtml.go b/uihtml.go index 5322480..95f5c8c 100644 --- a/uihtml.go +++ b/uihtml.go @@ -50,7 +50,7 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) { case func(*Request, string) error: // Deprecated: ClickFn if data != nil { elem.handlers = append(elem.handlers, eventFnWrapper{ - func(e *Element, wht what.What, val string) (err error) { + func(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Click { err = data(e.Request, e.jid.String()) } @@ -59,7 +59,7 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) { } case func(*Request, string, string) error: // Deprecated: InputTextFn if data != nil { - elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) { + elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { err = data(e.Request, e.jid.String(), val) } @@ -68,7 +68,7 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) { } case func(*Request, string, bool) error: // Deprecated: InputBoolFn if data != nil { - elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) { + elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v bool if val != "" { @@ -83,7 +83,7 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) { } case func(*Request, string, float64) error: // Deprecated: InputFloatFn if data != nil { - elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) { + elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v float64 if val != "" { @@ -98,7 +98,7 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) { } case func(*Request, string, time.Time) error: // Deprecated: InputDateFn if data != nil { - elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) { + elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v time.Time if val != "" { @@ -141,6 +141,6 @@ func (ui *UiHtml) JawsUpdate(e *Element) { } } -func (ui *UiHtml) JawsEvent(e *Element, wht what.What, val string) error { +func (ui *UiHtml) JawsEvent(e *Element, wht what.What, val string) (bool, error) { return callEventHandler(ui.Tag, e, wht, val) } diff --git a/uiinputbool.go b/uiinputbool.go index d827017..e37818f 100644 --- a/uiinputbool.go +++ b/uiinputbool.go @@ -34,7 +34,7 @@ func (ui *UiInputBool) JawsUpdate(e *Element) { } } -func (ui *UiInputBool) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiInputBool) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v bool if val != "" { @@ -45,9 +45,9 @@ func (ui *UiInputBool) JawsEvent(e *Element, wht what.What, val string) (err err ui.Last.Store(v) err = ui.BoolGetter.(BoolSetter).JawsSetBool(e, v) e.Dirty(ui.Tag) + if err != nil { + return + } } - if err == nil { - err = ui.UiHtml.JawsEvent(e, wht, val) - } - return + return ui.UiHtml.JawsEvent(e, wht, val) } diff --git a/uiinputdate.go b/uiinputdate.go index 54a468d..3c573cf 100644 --- a/uiinputdate.go +++ b/uiinputdate.go @@ -29,7 +29,7 @@ func (ui *UiInputDate) JawsUpdate(e *Element) { } } -func (ui *UiInputDate) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiInputDate) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v time.Time if val != "" { @@ -40,9 +40,9 @@ func (ui *UiInputDate) JawsEvent(e *Element, wht what.What, val string) (err err ui.Last.Store(v) err = ui.TimeGetter.(TimeSetter).JawsSetTime(e, v) e.Dirty(ui.Tag) + if err != nil { + return + } } - if err == nil { - err = ui.UiHtml.JawsEvent(e, wht, val) - } - return + return ui.UiHtml.JawsEvent(e, wht, val) } diff --git a/uiinputfloat.go b/uiinputfloat.go index 625af9b..c4a572b 100644 --- a/uiinputfloat.go +++ b/uiinputfloat.go @@ -29,7 +29,7 @@ func (ui *UiInputFloat) JawsUpdate(e *Element) { } } -func (ui *UiInputFloat) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiInputFloat) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { var v float64 if val != "" { @@ -40,9 +40,9 @@ func (ui *UiInputFloat) JawsEvent(e *Element, wht what.What, val string) (err er ui.Last.Store(v) err = ui.FloatGetter.(FloatSetter).JawsSetFloat(e, v) e.Dirty(ui.Tag) + if err != nil { + return + } } - if err == nil { - err = ui.UiHtml.JawsEvent(e, wht, val) - } - return + return ui.UiHtml.JawsEvent(e, wht, val) } diff --git a/uiinputtext.go b/uiinputtext.go index fe9b80c..b63c406 100644 --- a/uiinputtext.go +++ b/uiinputtext.go @@ -25,14 +25,14 @@ func (ui *UiInputText) JawsUpdate(e *Element) { } } -func (ui *UiInputText) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiInputText) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { ui.Last.Store(val) err = ui.StringGetter.(StringSetter).JawsSetString(e, val) e.Dirty(ui.Tag) + if err != nil { + return + } } - if err == nil { - err = ui.UiHtml.JawsEvent(e, wht, val) - } - return + return ui.UiHtml.JawsEvent(e, wht, val) } diff --git a/uiselect.go b/uiselect.go index 1150442..077c363 100644 --- a/uiselect.go +++ b/uiselect.go @@ -28,12 +28,15 @@ func (ui *UiSelect) JawsUpdate(e *Element) { ui.uiWrapContainer.JawsUpdate(e) } -func (ui *UiSelect) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiSelect) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { err = ui.uiWrapContainer.Container.(StringSetter).JawsSetString(e, val) e.Dirty(ui.Tag) + if err != nil { + return + } } - return + return ui.UiHtml.JawsEvent(e, wht, val) } func (rq *Request) Select(sh SelectHandler, params ...interface{}) template.HTML { diff --git a/uitextarea.go b/uitextarea.go index a929adb..d2e472f 100644 --- a/uitextarea.go +++ b/uitextarea.go @@ -22,12 +22,15 @@ func (ui *UiTextarea) JawsUpdate(e *Element) { e.SetInner(template.HTML(ui.JawsGetString(e))) // #nosec G203 } -func (ui *UiTextarea) JawsEvent(e *Element, wht what.What, val string) (err error) { +func (ui *UiTextarea) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) { if wht == what.Input { err = ui.StringGetter.(StringSetter).JawsSetString(e, val) e.Dirty(ui.Tag) + if err != nil { + return + } } - return + return ui.UiHtml.JawsEvent(e, wht, val) } func NewUiTextarea(g StringGetter) (ui *UiTextarea) { diff --git a/ws_test.go b/ws_test.go index 1963b6a..c836655 100644 --- a/ws_test.go +++ b/ws_test.go @@ -120,9 +120,9 @@ func TestWS_NormalExchange(t *testing.T) { gotCallCh := make(chan struct{}) - ts.rq.Register(("foo"), func(e *Element, evt what.What, val string) error { + ts.rq.Register(("foo"), func(e *Element, evt what.What, val string) (bool, error) { close(gotCallCh) - return fooError + return false, fooError }) conn, resp, err := websocket.Dial(ts.ctx, ts.Url(), nil)