-
Notifications
You must be signed in to change notification settings - Fork 1
/
element.go
188 lines (167 loc) · 5.39 KB
/
element.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package jaws
import (
"bytes"
"fmt"
"html/template"
"io"
"github.com/linkdata/jaws/jid"
"github.com/linkdata/jaws/what"
)
// An Element is an instance of a *Request, an UI object and a Jid.
type Element struct {
*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
handlers []EventHandler // custom event handlers registered, if any
}
func (e *Element) String() string {
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.Request.Tag(e, tags...)
}
// HasTag returns true if this Element has the given tag.
func (e *Element) HasTag(tag interface{}) bool {
return e.Request.HasTag(e, tag)
}
// Jid returns the JaWS ID for this Element, unique within it's Request.
func (e *Element) Jid() jid.Jid {
return e.jid
}
// Ui returns the UI object.
func (e *Element) Ui() UI {
return e.ui
}
// Render calls Request.JawsRender() for this Element.
func (e *Element) Render(w io.Writer, params []interface{}) error {
return e.Request.JawsRender(e, w, params)
}
func (e *Element) queue(wht what.What, data string) {
if len(e.wsQueue) < maxWsQueueLengthPerElement {
e.wsQueue = append(e.wsQueue, wsMsg{
Data: data,
Jid: e.jid,
What: wht,
})
} else {
e.Request.cancel(ErrWebsocketQueueOverflow)
}
}
// SetAttr queues sending a new attribute value
// to the browser for the Element with the given JaWS ID in this Request.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) SetAttr(attr, val string) {
e.queue(what.SAttr, attr+"\n"+val)
}
// RemoveAttr queues sending a request to remove an attribute
// to the browser for the Element with the given JaWS ID in this Request.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) RemoveAttr(attr string) {
e.queue(what.RAttr, attr)
}
// SetClass a queues sending a class
// to the browser for the Element with the given JaWS ID in this Request.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) SetClass(cls string) {
e.queue(what.SClass, cls)
}
// RemoveClass queues sending a request to remove a class
// to the browser for the Element with the given JaWS ID in this Request.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) RemoveClass(cls string) {
e.queue(what.RClass, cls)
}
// SetInner queues sending a new inner HTML content
// to the browser for the Element.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) SetInner(innerHtml template.HTML) {
e.queue(what.Inner, string(innerHtml))
}
// SetValue queues sending a new current input value in textual form
// to the browser for the Element with the given JaWS ID in this Request.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) SetValue(val string) {
e.queue(what.Value, val)
}
// Replace replaces the elements entire HTML DOM node with new HTML code.
// If the HTML code doesn't seem to contain correct HTML ID, it panics.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) Replace(htmlCode template.HTML) {
var b []byte
b = append(b, "id="...)
b = e.Jid().AppendQuote(b)
if !bytes.Contains([]byte(htmlCode), b) {
panic(fmt.Errorf("jaws: Element.Replace(): expected HTML " + string(b)))
}
e.queue(what.Replace, string(htmlCode))
}
// Append appends a new HTML element as a child to the current one.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) Append(htmlCode template.HTML) {
e.queue(what.Append, string(htmlCode))
}
// Order reorders the HTML elements.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) Order(jidList []jid.Jid) {
if len(jidList) > 0 {
var b []byte
for i, jid := range jidList {
if i > 0 {
b = append(b, ' ')
}
b = jid.Append(b)
}
e.queue(what.Order, string(b))
}
}
// Remove requests that the HTML child with the given HTML ID of this Element
// is removed from the Request and it's HTML element from the browser.
//
// Call this only during JawsRender() or JawsUpdate() processing.
func (e *Element) Remove(htmlId string) {
e.queue(what.Remove, htmlId)
}
// ParseParams parses the parameters passed to UI() when creating a new Element,
// setting event handlers and returning a list of HTML attributes.
func (e *Element) ParseParams(params []interface{}) (attrs []template.HTMLAttr) {
for i := range params {
switch data := params[i].(type) {
case template.HTMLAttr:
attrs = append(attrs, data)
case []template.HTMLAttr:
attrs = append(attrs, data...)
case string:
attrs = append(attrs, template.HTMLAttr(data)) // #nosec G203
case []string:
for _, s := range data {
attrs = append(attrs, template.HTMLAttr(s)) // #nosec G203
}
case EventFn:
if data != nil {
e.handlers = append(e.handlers, eventFnWrapper{data})
}
default:
if h, ok := data.(ClickHandler); ok {
e.handlers = append(e.handlers, clickHandlerWapper{h})
}
if h, ok := data.(EventHandler); ok {
e.handlers = append(e.handlers, h)
}
e.Tag(data)
}
}
return
}