-
Notifications
You must be signed in to change notification settings - Fork 6
/
list_checkbox.go
291 lines (261 loc) · 9.07 KB
/
list_checkbox.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
package control
import (
"bytes"
"context"
"github.com/goradd/goradd/pkg/html"
"github.com/goradd/goradd/pkg/page"
"strings"
)
type CheckboxListI interface {
MultiselectListI
SetColumnCount(int) CheckboxListI
SetLayoutDirection(direction LayoutDirection) CheckboxListI
SetLabelDrawingMode(mode html.LabelDrawingMode) CheckboxListI
SetIsScrolling(s bool) CheckboxListI
SetRowClass(c string) CheckboxListI
RenderItems(items []*ListItem) string
RenderItem(item *ListItem) string
}
// CheckboxList is a multi-select control that presents its choices as a list of checkboxes.
// Styling is provided by divs and spans that you can provide css for in your style sheets. The
// goradd.css file has default styling to handle the basics. It wraps the whole thing in a div that can be set
// to scroll as well, so that the final structure can be styled like a multi-column table, or a single-column
// scrolling list much like a standard html select list.
type CheckboxList struct {
MultiselectList
// columnCount is the number of columns to force the list to display. It specifies the maximum number
// of objects placed in each row wrapper. Keeping this at zero (the default)
// will result in no row wrappers.
columnCount int
// direction controls how items are placed when there are columns.
direction LayoutDirection
// labelDrawingMode determines how labels are drawn. The default is to use the global setting.
labelDrawingMode html.LabelDrawingMode
// isScrolling determines if we are going to let the list scroll. You will need to limit the size of the
// control for scrolling to happen.
isScrolling bool
// rowClass is the class assigned to the div wrapper around each row.
rowClass string
}
// NewCheckboxList creates a new CheckboxList
func NewCheckboxList(parent page.ControlI, id string) *CheckboxList {
l := &CheckboxList{}
l.Self = l
l.Init(parent, id)
return l
}
// Init is called by subclasses
func (l *CheckboxList) Init(parent page.ControlI, id string) {
l.MultiselectList.Init(parent, id)
l.Tag = "div"
l.rowClass = "gr-cbl-row"
l.labelDrawingMode = page.DefaultCheckboxLabelDrawingMode
}
func (l *CheckboxList) this() CheckboxListI {
return l.Self.(CheckboxListI)
}
// SetColumnCount sets the number of columns to use to display the list. Items will be evenly distributed
// across the columns.
func (l *CheckboxList) SetColumnCount(columns int) CheckboxListI {
if l.columnCount < 0 {
panic("Columns must be at least 0.")
}
l.columnCount = columns
l.Refresh()
return l.this()
}
// ColumnCount returns the current column count.
func (l *CheckboxList) ColumnCount() int {
return l.columnCount
}
// SetLayoutDirection specifies how items are distributed across the columns.
func (l *CheckboxList) SetLayoutDirection(direction LayoutDirection) CheckboxListI {
l.direction = direction
l.Refresh()
return l.this()
}
// LayoutDirection returns the direction of how items are spread across the columns.
func (l *CheckboxList) LayoutDirection() LayoutDirection {
return l.direction
}
// SetLabelDrawingMode indicates how labels for each of the checkboxes are drawn.
func (l *CheckboxList) SetLabelDrawingMode(mode html.LabelDrawingMode) CheckboxListI {
l.labelDrawingMode = mode
l.Refresh()
return l.this()
}
// SetIsScrolling sets whether the list will scroll if it gets bigger than its bounding box.
// You will need to style the bounding box to give it limits, or else it will simply grow as
// big as the list.
func (l *CheckboxList) SetIsScrolling(s bool) CheckboxListI {
l.isScrolling = s
l.Refresh()
return l.this()
}
// SetRowClass sets the class to the div wrapper around each row. If blank, will be given
// a default.
func (l *CheckboxList) SetRowClass(c string) CheckboxListI {
l.rowClass = c
l.Refresh()
return l.this()
}
// DrawingAttributes retrieves the tag's attributes at draw time.
// You should not normally need to call this, and the
// attributes are disposed of after drawing, so they are essentially read-only.
func (l *CheckboxList) DrawingAttributes(ctx context.Context) html.Attributes {
a := l.ControlBase.DrawingAttributes(ctx)
a.SetDataAttribute("grctl", "checkboxlist")
a.AddClass("gr-cbl")
if l.isScrolling {
a.AddClass("gr-cbl-scroller")
}
return a
}
// DrawInnerHtml is called by the framework to draw the contents of the list.
func (l *CheckboxList) DrawInnerHtml(ctx context.Context, buf *bytes.Buffer) (err error) {
h := l.this().RenderItems(l.items)
h = html.RenderTag("div", html.NewAttributes().SetClass("gr-cbl-table").SetID(l.ID()+"_cbl"), h)
buf.WriteString(h)
return nil
}
func (l *CheckboxList) RenderItems(items []*ListItem) string {
var hItems []string
for _,item := range items {
hItems = append(hItems, l.this().RenderItem(item))
}
if l.columnCount == 0 {
return strings.Join(hItems, "")
}
b := GridLayoutBuilder{}
return b.Items(hItems).
ColumnCount(l.columnCount).
Direction(l.direction).
RowClass(l.rowClass).
Build()
}
// RenderItem is called by the framework to render a single item in the list.
func (l *CheckboxList) RenderItem(item *ListItem) (h string) {
_, selected := l.selectedValues[item.Value()]
h = renderCheckItemControl(item, "checkbox", l.labelDrawingMode, selected, l.ID())
h = renderCell(item, h, l.columnCount > 0)
return
}
// UpdateFormValues is used by the framework to cause the control to retrieve its values from the form
func (l *CheckboxList) UpdateFormValues(ctx context.Context) {
controlID := l.ID()
grctx := page.GetContext(ctx)
if grctx.RequestMode() == page.Server {
// Using name attribute to return rendered checkboxes that are turned on.
if v, ok := grctx.FormValues(controlID); ok {
l.SetSelectedValuesNoRefresh(v)
}
}
}
func (l *CheckboxList) Serialize(e page.Encoder) (err error) {
if err = l.MultiselectList.Serialize(e); err != nil {
return
}
if err = e.Encode(l.columnCount); err != nil {
return
}
if err = e.Encode(l.direction); err != nil {
return
}
if err = e.Encode(l.labelDrawingMode); err != nil {
return
}
if err = e.Encode(l.isScrolling); err != nil {
return
}
if err = e.Encode(l.rowClass); err != nil {
return
}
return
}
func (l *CheckboxList) Deserialize(dec page.Decoder) (err error) {
if err = l.MultiselectList.Deserialize(dec); err != nil {
return
}
if err = dec.Decode(&l.columnCount); err != nil {
return
}
if err = dec.Decode(&l.direction); err != nil {
return
}
if err = dec.Decode(&l.labelDrawingMode); err != nil {
return
}
if err = dec.Decode(&l.isScrolling); err != nil {
return
}
if err = dec.Decode(&l.rowClass); err != nil {
return
}
return
}
type CheckboxListCreator struct {
ID string
// Items is a static list of labels and values that will be in the list. Or, use a DataProvider to dynamically generate the items.
Items []ListValue
// DataProvider is the control that will dynamically provide the data for the list and that implements the DataBinder interface.
DataProvider DataBinder
// DataProviderID is the id of a control that will dynamically provide the data for the list and that implements the DataBinder interface.
DataProviderID string
// ColumnCount specifies how many columns to show
ColumnCount int
// LayoutDirection determines how the items are arranged in the columns
LayoutDirection LayoutDirection
// LabelDrawingMode specifies how the labels on the radio buttons will be associated with the buttons
LabelDrawingMode html.LabelDrawingMode
// IsScrolling will give the inner div a vertical scroll style. You will need to style the height of the outer control to have a fixed style as well.
IsScrolling bool
// RowClass is the class assigned to each row
RowClass string
// Value is the initial value of the textbox. Often its best to load the value in a separate Load step after creating the control.
Value string
// SaveState saves the selected value so that it is restored if the form is returned to.
SaveState bool
page.ControlOptions
}
// Create is called by the framework to create a new control from the Creator. You
// do not normally need to call this.
func (c CheckboxListCreator) Create(ctx context.Context, parent page.ControlI) page.ControlI {
ctrl := NewCheckboxList(parent, c.ID)
c.Init(ctx, ctrl)
return ctrl
}
func (c CheckboxListCreator) Init(ctx context.Context, ctrl CheckboxListI) {
if c.Items != nil {
ctrl.AddListItems(c.Items)
}
if c.DataProvider != nil {
ctrl.SetDataProvider(c.DataProvider)
} else if c.DataProviderID != "" {
provider := ctrl.Page().GetControl(c.DataProviderID).(DataBinder)
ctrl.SetDataProvider(provider)
}
if c.ColumnCount != 0 {
ctrl.SetColumnCount(c.ColumnCount)
}
ctrl.SetLayoutDirection(c.LayoutDirection)
if c.LabelDrawingMode != html.LabelDefault {
ctrl.SetLabelDrawingMode(c.LabelDrawingMode)
}
if c.IsScrolling {
ctrl.SetIsScrolling(true)
}
if c.RowClass != "" {
ctrl.SetRowClass(c.RowClass)
}
ctrl.ApplyOptions(ctx, c.ControlOptions)
if c.SaveState {
ctrl.SaveState(ctx, c.SaveState)
}
}
// GetRadioList is a convenience method to return the control with the given id from the page.
func GetCheckboxList(c page.ControlI, id string) *CheckboxList {
return c.Page().GetControl(id).(*CheckboxList)
}
func init() {
page.RegisterControl(&CheckboxList{})
}