diff --git a/element.go b/element.go
index 905444e..fbebcc5 100644
--- a/element.go
+++ b/element.go
@@ -12,9 +12,9 @@ import (
// An Element is an instance of a *Request, an UI object and a Jid.
type Element struct {
- ui UI // (read-only) the UI object
- jid jid.Jid // (read-only) JaWS ID, unique to this Element within it's Request
- rq *Request // (read-only) the Request the Element belongs to
+ *Request // (read-only) the Request the Element belongs to
+ ui UI // (read-only) the UI object
+ jid jid.Jid // (read-only) JaWS ID, unique to this Element within it's Request
// internals
updating bool // about to have Update() called
wsQueue []wsMsg // changes queued
@@ -22,47 +22,17 @@ type Element struct {
}
func (e *Element) String() string {
- return fmt.Sprintf("Element{%T, id=%q, Tags: %v}", e.ui, e.jid, e.rq.TagsOf(e))
-}
-
-// Jaws returns the Jaws the Element belongs to.
-func (e *Element) Jaws() *Jaws {
- return e.rq.Jaws
-}
-
-// Request returns the Request the Element belongs to.
-func (e *Element) Request() *Request {
- return e.rq
-}
-
-// Session returns the Elements's Session, or nil.
-func (e *Element) Session() *Session {
- return e.rq.Session()
-}
-
-// Get calls Session().Get()
-func (e *Element) Get(key string) (val interface{}) {
- return e.Session().Get(key)
-}
-
-// Set calls Session().Get()
-func (e *Element) Set(key string, val interface{}) {
- e.Session().Set(key, val)
-}
-
-// Dirty calls Request().Dirty()
-func (e *Element) Dirty(tags ...interface{}) {
- e.rq.Dirty(tags...)
+ return fmt.Sprintf("Element{%T, id=%q, Tags: %v}", e.ui, e.jid, e.Request.TagsOf(e))
}
// Tag adds the given tags to the Element.
func (e *Element) Tag(tags ...interface{}) {
- e.rq.Tag(e, tags...)
+ e.Request.Tag(e, tags...)
}
// HasTag returns true if this Element has the given tag.
func (e *Element) HasTag(tag interface{}) bool {
- return e.rq.HasTag(e, tag)
+ return e.Request.HasTag(e, tag)
}
// Jid returns the JaWS ID for this Element, unique within it's Request.
@@ -77,7 +47,7 @@ func (e *Element) Ui() UI {
// Render calls Request.JawsRender() for this Element.
func (e *Element) Render(w io.Writer, params []interface{}) error {
- return e.rq.JawsRender(e, w, params)
+ return e.Request.JawsRender(e, w, params)
}
func (e *Element) queue(wht what.What, data string) {
@@ -88,7 +58,7 @@ func (e *Element) queue(wht what.What, data string) {
What: wht,
})
} else {
- e.rq.cancel(ErrWebsocketQueueOverflow)
+ e.Request.cancel(ErrWebsocketQueueOverflow)
}
}
diff --git a/element_test.go b/element_test.go
index 697c7c7..4f4c4a0 100644
--- a/element_test.go
+++ b/element_test.go
@@ -62,8 +62,8 @@ func TestElement_helpers(t *testing.T) {
tss := &testUi{}
e := rq.NewElement(tss)
- is.Equal(e.Jaws(), rq.jw.Jaws)
- is.Equal(e.Request(), rq.Request)
+ is.Equal(e.Jaws, rq.jw.Jaws)
+ is.Equal(e.Request, rq.Request)
is.Equal(e.Session(), nil)
e.Set("foo", "bar") // no session, so no effect
is.Equal(e.Get("foo"), nil)
diff --git a/jaws.js b/jaws.js
index d536d86..04ed35e 100644
--- a/jaws.js
+++ b/jaws.js
@@ -188,8 +188,7 @@ function jawsLost() {
innerHTML += '. Trying to reconnect.';
var elem = document.getElementById('jaws-lost');
if (elem == null) {
- elem = jawsElement('
' +
- innerHTML + '
');
+ elem = jawsElement('' + innerHTML + '
');
document.body.prepend(elem);
document.body.scrollTop = document.documentElement.scrollTop = 0;
} else {
diff --git a/jawsboot/jawsboot_test.go b/jawsboot/jawsboot_test.go
index 5d289a5..b2b9f5e 100644
--- a/jawsboot/jawsboot_test.go
+++ b/jawsboot/jawsboot_test.go
@@ -16,7 +16,9 @@ func TestJawsBoot_Setup(t *testing.T) {
}
rq := jw.NewRequest(nil)
- txt := string(rq.HeadHTML())
+ var sb strings.Builder
+ rq.Writer(&sb).HeadHTML()
+ txt := sb.String()
if !strings.Contains(txt, rq.JawsKeyString()) {
t.Error(txt)
}
diff --git a/js.go b/js.go
index 22ef751..fee2443 100644
--- a/js.go
+++ b/js.go
@@ -54,6 +54,7 @@ func JawsKeyValue(jawsKey string) uint64 {
const jsLoader = `.forEach(function(c){var e=document.createElement("script");e.src=c;e.async=!1;document.head.appendChild(e);});`
// HeadHTML returns HTML code to load the given scripts and CSS files efficiently,
+// as well as a basic CSS "jaws-alert" class for JaWS to use.
func HeadHTML(js []string, css []string) string {
var s []byte
@@ -67,6 +68,10 @@ func HeadHTML(js []string, css []string) string {
s = strconv.AppendQuote(s, e)
s = append(s, " as=\"script\">\n"...)
}
+ s = append(s, `
+`...)
s = append(s, "`
- return template.HTML(s) // #nosec G203
+// HeadHTML writes the HTML code needed in the HTML page's HEAD section.
+func (rq *Request) HeadHTML(w io.Writer) (err error) {
+ if _, err = w.Write([]byte(rq.Jaws.headPrefix)); err == nil {
+ if _, err = w.Write([]byte(rq.JawsKeyString())); err == nil {
+ _, err = w.Write([]byte(`";`))
+ }
+ }
+ return
}
// GetConnectFn returns the currently set ConnectFn. That function will be called before starting the WebSocket tunnel if not nil.
@@ -298,9 +301,9 @@ var nextJid Jid
func (rq *Request) newElementLocked(ui UI) (elem *Element) {
elem = &Element{
- jid: Jid(atomic.AddInt64((*int64)(&nextJid), 1)),
- ui: ui,
- rq: rq,
+ jid: Jid(atomic.AddInt64((*int64)(&nextJid), 1)),
+ ui: ui,
+ Request: rq,
}
rq.elems = append(rq.elems, elem)
return
@@ -364,8 +367,8 @@ func (rq *Request) tagExpanded(elem *Element, expandedtags []interface{}) {
// Tag adds the given tags to the given Element.
func (rq *Request) Tag(elem *Element, tags ...interface{}) {
- if elem != nil && len(tags) > 0 && elem.rq == rq {
- rq.tagExpanded(elem, MustTagExpand(elem.rq, tags))
+ if elem != nil && len(tags) > 0 && elem.Request == rq {
+ rq.tagExpanded(elem, MustTagExpand(elem.Request, tags))
}
}
@@ -635,7 +638,7 @@ func (rq *Request) sendQueue(outboundCh chan<- string, wsQueue []wsMsg) []wsMsg
}
func (rq *Request) deleteElementLocked(e *Element) {
- e.rq = nil
+ e.Request = nil
rq.elems = slices.DeleteFunc(rq.elems, func(elem *Element) bool { return elem == e })
for k := range rq.tagMap {
rq.tagMap[k] = slices.DeleteFunc(rq.tagMap[k], func(elem *Element) bool { return elem == e })
@@ -695,5 +698,5 @@ func (rq *Request) onConnect() (err error) {
}
func (rq *Request) Writer(w io.Writer) RequestWriter {
- return RequestWriter{Request: rq, Writer: w}
+ return RequestWriter{rq: rq, Writer: w}
}
diff --git a/request_test.go b/request_test.go
index 5c1a1e8..75dc287 100644
--- a/request_test.go
+++ b/request_test.go
@@ -56,7 +56,9 @@ func TestRequest_HeadHTML(t *testing.T) {
rq := jw.NewRequest(nil)
defer jw.recycle(rq)
- txt := rq.HeadHTML()
+ var sb strings.Builder
+ rq.Writer(&sb).HeadHTML()
+ txt := sb.String()
is.Equal(strings.Contains(string(txt), rq.JawsKeyString()), true)
is.Equal(strings.Contains(string(txt), JavascriptPath), true)
}
diff --git a/requestwriter.go b/requestwriter.go
index 351271d..03cff88 100644
--- a/requestwriter.go
+++ b/requestwriter.go
@@ -1,12 +1,45 @@
package jaws
-import "io"
+import (
+ "io"
+ "net/http"
+)
type RequestWriter struct {
- *Request
+ rq *Request
io.Writer
}
func (rw RequestWriter) UI(ui UI, params ...interface{}) error {
- return rw.JawsRender(rw.NewElement(ui), rw.Writer, params)
+ return rw.rq.JawsRender(rw.rq.NewElement(ui), rw.Writer, params)
+}
+
+// Request returns the current jaws.Request.
+func (rw RequestWriter) Request() *Request {
+ return rw.rq
+}
+
+// Initial returns the initial http.Request.
+func (rw RequestWriter) Initial() *http.Request {
+ return rw.Request().Initial
+}
+
+// HeadHTML outputs the HTML code needed in the HEAD section.
+func (rw RequestWriter) HeadHTML() error {
+ return rw.Request().HeadHTML(rw)
+}
+
+// Session returns the Requests's Session, or nil.
+func (rw RequestWriter) Session() *Session {
+ return rw.Request().Session()
+}
+
+// Get calls Request().Get()
+func (rw RequestWriter) Get(key string) (val interface{}) {
+ return rw.Request().Get(key)
+}
+
+// Set calls Request().Set()
+func (rw RequestWriter) Set(key string, val interface{}) {
+ rw.Request().Set(key, val)
}
diff --git a/session_test.go b/session_test.go
index 8edd8e8..a1387d9 100644
--- a/session_test.go
+++ b/session_test.go
@@ -70,8 +70,9 @@ func TestSession_Use(t *testing.T) {
return
}
+ var sb strings.Builder
sess := jw.GetSession(r)
- rq := jw.NewRequest(r)
+ rq := jw.NewRequest(r).Writer(&sb)
if sess != rq.Session() {
t.Error(sess)
}
@@ -100,7 +101,7 @@ func TestSession_Use(t *testing.T) {
rq.Set("bar", "quux")
}
w.WriteHeader(http.StatusOK)
- jw.UseRequest(rq.JawsKey, r)
+ jw.UseRequest(rq.Request().JawsKey, r)
})
srv := httptest.NewServer(h)
@@ -276,7 +277,7 @@ func TestSession_Delete(t *testing.T) {
}
ts.rq.Register("byebye", func(e *Element, evt what.What, val string) error {
- sess2 := ts.jw.GetSession(e.Request().Initial)
+ sess2 := ts.jw.GetSession(e.Request.Initial)
if x := sess2; x != ts.sess {
t.Error(x)
}
diff --git a/template.go b/template.go
index d0d25c1..4db9607 100644
--- a/template.go
+++ b/template.go
@@ -40,8 +40,8 @@ func (t Template) String() string {
}
func (t Template) JawsRender(e *Element, w io.Writer, params []interface{}) error {
- if expandedtags, err := TagExpand(e.Request(), t.Dot); err != ErrIllegalTagType {
- e.Request().tagExpanded(e, expandedtags)
+ if expandedtags, err := TagExpand(e.Request, t.Dot); err != ErrIllegalTagType {
+ e.Request.tagExpanded(e, expandedtags)
}
var sb strings.Builder
for _, s := range parseParams(e, params) {
@@ -51,7 +51,7 @@ func (t Template) JawsRender(e *Element, w io.Writer, params []interface{}) erro
attrs := template.HTMLAttr(sb.String()) // #nosec G203
return t.Execute(w, With{
Element: e,
- RequestWriter: e.Request().Writer(w),
+ RequestWriter: e.Request.Writer(w),
Dot: t.Dot,
Attrs: attrs,
})
diff --git a/ui.go b/ui.go
index 81cc575..95c2396 100644
--- a/ui.go
+++ b/ui.go
@@ -18,7 +18,7 @@ func (rq *Request) JawsRender(elem *Element, w io.Writer, params []interface{})
if rq.Jaws.Debug {
var sb strings.Builder
_, _ = fmt.Fprintf(&sb, "