diff --git a/gwu/doc.go b/gwu/doc.go index a488373..86c5f0b 100644 --- a/gwu/doc.go +++ b/gwu/doc.go @@ -398,7 +398,7 @@ package gwu // Gowut version information. const ( - GowutVersion = "1.1.0" // Gowut version: major.minor.maintenance[-dev] - GowutReleaseDate = "2016-03-14 CET" // Gowut release date + GowutVersion = "v1.1.1" // Gowut version: "v"major.minor.maintenance[-dev] + GowutReleaseDate = "2016-07-28 CET" // Gowut release date GowutRelDateLayout = "2006-01-02 MST" // Gowut release date layout (for time.Parse()) ) diff --git a/gwu/event.go b/gwu/event.go index 8e9853f..fb7bb5d 100644 --- a/gwu/event.go +++ b/gwu/event.go @@ -18,6 +18,7 @@ package gwu import ( + "net/http" "strconv" ) @@ -283,6 +284,33 @@ type Event interface { forkEvent(etype EventType, src Comp) Event } +// HasRequestResponse defines methods to acquire / access +// http.ResponseWriter and http.Request from something that supports this. +// +// The concrete type that implements Event does implement this too, +// but this is not added to the Event interface intentionally to not urge the use of this. +// Users should not rely on this as in a future implementation there might not be +// a response and request associated with an event. +// But this may be useful in certain scenarios, such as you need to know the client IP address, +// or you want to use custom authentication that needs the request/response. +// +// To get access to these methods, simply use a type assertion, asserting that the event value +// implements this interface. For example: +// +// someButton.AddEHandlerFunc(func(e gwu.Event) { +// if hrr, ok := e.(gwu.HasRequestResponse); ok { +// req := hrr.Request() +// log.Println("Client addr:", req.RemoteAddr) +// } +// }, gwu.ETypeClick) +type HasRequestResponse interface { + // ResponseWriter returns the associated HTTP response writer. + ResponseWriter() http.ResponseWriter + + // Request returns the associated HTTP request. + Request() *http.Request +} + // Event implementation. type eventImpl struct { etype EventType // Event type @@ -308,12 +336,16 @@ type sharedEvtData struct { dirtyComps map[ID]Comp // The dirty components focusedComp Comp // Component to be focused after the event processing session Session // Session + + rw http.ResponseWriter // ResponseWriter of the HTTP request the event was created from + req *http.Request // Request of the HTTP request the event was created from } // newEventImpl creates a new eventImpl -func newEventImpl(etype EventType, src Comp, server *serverImpl, session Session) *eventImpl { +func newEventImpl(etype EventType, src Comp, server *serverImpl, session Session, + rw http.ResponseWriter, req *http.Request) *eventImpl { e := eventImpl{etype: etype, src: src, - shared: &sharedEvtData{server: server, dirtyComps: make(map[ID]Comp, 2), session: session}} + shared: &sharedEvtData{server: server, dirtyComps: make(map[ID]Comp, 2), session: session, rw: rw, req: req}} return &e } @@ -429,6 +461,14 @@ func (e *eventImpl) forkEvent(etype EventType, src Comp) Event { shared: e.shared} } +func (e *eventImpl) ResponseWriter() http.ResponseWriter { + return e.shared.rw +} + +func (e *eventImpl) Request() *http.Request { + return e.shared.req +} + // Handler function wrapper type handlerFuncWrapper struct { hf func(e Event) // The handler function to be called as part of implementing the EventHandler interface diff --git a/gwu/listbox.go b/gwu/listbox.go index d76a25c..3e5e353 100644 --- a/gwu/listbox.go +++ b/gwu/listbox.go @@ -181,12 +181,12 @@ func (c *listBoxImpl) ClearSelected() { func (c *listBoxImpl) preprocessEvent(event Event, r *http.Request) { value := r.FormValue(paramCompValue) + c.ClearSelected() if len(value) == 0 { return } // Set selected indices - c.ClearSelected() for _, sidx := range strings.Split(value, ",") { if idx, err := strconv.Atoi(sidx); err == nil { c.selected[idx] = true diff --git a/gwu/server.go b/gwu/server.go index bda7d72..eb011ab 100644 --- a/gwu/server.go +++ b/gwu/server.go @@ -646,7 +646,7 @@ func (s *serverImpl) serveHTTP(w http.ResponseWriter, r *http.Request) { // renderWinList renders the window list of a session as HTML document with clickable links. func (s *serverImpl) renderWinList(wr http.ResponseWriter, r *http.Request, sess Session) { if s.logger != nil { - s.logger.Println("\tRending windows list.") + s.logger.Println("\tRendering windows list.") } wr.Header().Set("Content-Type", "text/html; charset=utf-8") @@ -745,7 +745,7 @@ func (s *serverImpl) handleEvent(sess Session, win Window, wr http.ResponseWrite s.logger.Println("\tEvent from comp:", id, " event:", etype) } - event := newEventImpl(EventType(etype), comp, s, sess) + event := newEventImpl(EventType(etype), comp, s, sess, wr, r) shared := event.shared event.x = parseIntParam(r, paramMouseX) diff --git a/gwu/server_start.go b/gwu/server_start.go index 82f3257..3f25aef 100644 --- a/gwu/server_start.go +++ b/gwu/server_start.go @@ -38,7 +38,7 @@ func open(url string) error { case "darwin": cmd = "open" default: // "linux", "freebsd", "openbsd", "netbsd" - cmd = "xgd-open" + cmd = "xdg-open" } args = append(args, url) return exec.Command(cmd, args...).Start() @@ -59,7 +59,9 @@ func (s *serverImpl) Start(openWins ...string) error { } for _, winName := range openWins { - open(s.appUrl + winName) + if err := open(s.appUrl + winName); err != nil { + s.logger.Printf("Opening window '%s' err: %v\n", s.appUrl+winName, err) + } } go s.sessCleaner()