-
Notifications
You must be signed in to change notification settings - Fork 6
/
table_select.go
241 lines (215 loc) · 7.39 KB
/
table_select.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
package control
import (
"context"
"fmt"
"github.com/goradd/gengen/pkg/maps"
"github.com/goradd/goradd/pkg/config"
"github.com/goradd/goradd/pkg/html"
"github.com/goradd/goradd/pkg/page"
"github.com/goradd/goradd/pkg/page/action"
"github.com/goradd/goradd/pkg/page/event"
)
// PrimaryKeyer is an interface that is often implemented by model objects.
type PrimaryKeyer interface {
PrimaryKey() string
}
type SelectTableI interface {
TableI
SetSelectedID(id string) SelectTableI
}
// SelectTable is a table that is row selectable. To detect a row selection, trigger on event.RowSelected
type SelectTable struct {
Table
selectedID string
}
func NewSelectTable(parent page.ControlI, id string) *SelectTable {
t := &SelectTable{}
t.Self = t
t.Init(parent, id)
return t
}
func (t *SelectTable) Init(parent page.ControlI, id string) {
t.Table.Init(parent, id)
t.ParentForm().AddJavaScriptFile(config.GoraddAssets() + "/js/goradd-scrollIntoView.js", false, nil)
t.ParentForm().AddJavaScriptFile(config.GoraddAssets() + "/js/table-select.js", false, nil)
t.SetAttribute("tabindex", 0); // Make the entire table focusable and selectable. This can be overridden later if needed.
t.AddClass("gr-clickable-rows")
}
func (t *SelectTable) this() SelectTableI {
return t.Self.(SelectTableI)
}
func (t *SelectTable) GetRowAttributes(row int, data interface{}) (a html.Attributes) {
var id string
if t.RowStyler() != nil {
a = t.RowStyler().TableRowAttributes(row, data)
id = a.Get("id") // styler might be giving us an id
} else {
a = html.NewAttributes()
}
// try to guess the id from the data
if id == "" {
switch obj := data.(type) {
case IDer:
id = obj.ID()
case PrimaryKeyer:
id = obj.PrimaryKey()
case map[string]string:
id, _ = obj["id"]
case maps.StringGetter:
id = obj.Get("id")
}
}
if id != "" {
// TODO: If configured, encrypt the id so its not publicly showing database ids
a.SetDataAttribute("id", id)
// We need an actual id for aria features
a.SetID(t.ID() + "_" + id)
} else {
a.AddClass("nosel")
}
a.Set("role", "option")
return a
}
func (t *SelectTable) DrawingAttributes(ctx context.Context) html.Attributes {
a := t.Table.DrawingAttributes(ctx)
a.SetDataAttribute("grctl", "selecttable")
a.Set("role", "listbox")
a.SetDataAttribute("grWidget", "goradd.selectTable")
if t.selectedID != "" {
a.SetDataAttribute("grOptSelectedId", t.selectedID)
}
return a
}
func (t *SelectTable) UpdateFormValues(ctx *page.Context) {
if data := ctx.CustomControlValue(t.ID(), "selectedId"); data != nil {
t.selectedID = fmt.Sprintf("%v", data)
}
}
func (t *SelectTable) SelectedID() string {
return t.selectedID
}
func (t *SelectTable) SetSelectedID(id string) SelectTableI {
t.selectedID = id
t.ExecuteWidgetFunction("option", "selectedId", id)
return t.this()
}
func (t *SelectTable) MarshalState(m maps.Setter) {
m.Set("selId", t.selectedID)
}
func (t *SelectTable) UnmarshalState(m maps.Loader) {
if v, ok := m.Load("selId"); ok {
if id, ok2 := v.(string); ok2 {
t.selectedID = id
}
}
}
func (t *SelectTable) Serialize(e page.Encoder) (err error) {
if err = t.Table.Serialize(e); err != nil {
return
}
if err = e.Encode(t.selectedID); err != nil {
return
}
return
}
func (t *SelectTable) Deserialize(dec page.Decoder) (err error) {
if err = t.Table.Deserialize(dec); err != nil {
return
}
if err = dec.Decode(&t.selectedID); err != nil {
return
}
return
}
// SelectTableCreator is the initialization structure for declarative creation of tables
type SelectTableCreator struct {
// ID is the control id
ID string
// HasColTags will make the table render <col> tags
HasColTags bool
// Caption is the content of the caption tag, and can either be a string, or a data pager
Caption interface{}
// HideIfEmpty will hide the table completely if it has no data. Otherwise, the table and headers will be shown, but no data rows
HideIfEmpty bool
// HeaderRowCount is the number of header rows. You must set this to at least 1 to show header rows.
HeaderRowCount int
// FooterRowCount is the number of footer rows.
FooterRowCount int
// RowStyler returns the attributes to be used in a cell.
RowStyler TableRowAttributer
// RowStylerID is a control id for the control that will be the RowStyler of the table.
RowStylerID string
// HeaderRowStyler returns the attributes to be used in a header cell.
HeaderRowStyler TableHeaderRowAttributer
// HeaderRowStylerID is a control id for the control that will be the HeaderRowStyler of the table.
HeaderRowStylerID string
// FooterRowStyler returns the attributes to be used in a footer cell. It can be either a control id or a TableFooterRowAttributer.
FooterRowStyler TableFooterRowAttributer
// FooterRowStylerID is a control id for the control that will be the FooterRowStyler of the table.
FooterRowStylerID string
// Columns are the column creators that will add columns to the table
Columns []ColumnCreator
// 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
// Data is the actual data for the table, and should be a slice of objects
Data interface{}
// Sortable will make the table sortable
Sortable bool
// SortHistoryLimit will set how many columns deep we will remember the sorting for multi-level sorts
SortHistoryLimit int
page.ControlOptions
// OnRowSelected is the action to take when the row is selected
OnRowSelected action.ActionI
// SelectedID is the row id that will start as the selection
SelectedID string
// SaveState will cause the table to remember the selection
SaveState bool
}
// Create is called by the framework to create a new control from the Creator. You
// do not normally need to call this.
func (c SelectTableCreator) Create(ctx context.Context, parent page.ControlI) page.ControlI {
ctrl := NewSelectTable(parent, c.ID)
c.Init(ctx, ctrl)
return ctrl
}
// Init is called by implementations of Buttons to initialize a control with the
// creator. You do not normally need to call this.
func (c SelectTableCreator) Init(ctx context.Context, ctrl SelectTableI) {
sub := TableCreator {
ID: c.ID,
HasColTags: c.HasColTags,
Caption: c.Caption,
HideIfEmpty: c.HideIfEmpty,
HeaderRowCount: c.HeaderRowCount,
FooterRowCount: c.FooterRowCount,
RowStyler: c.RowStyler,
HeaderRowStyler: c.HeaderRowStyler,
FooterRowStyler: c.FooterRowStyler,
Columns: c.Columns,
DataProvider: c.DataProvider,
DataProviderID: c.DataProviderID,
Data: c.Data,
Sortable: c.Sortable,
SortHistoryLimit: c.SortHistoryLimit,
ControlOptions: c.ControlOptions,
}
sub.Init(ctx, ctrl)
if c.SelectedID != "" {
ctrl.SetSelectedID(c.SelectedID)
}
if c.SaveState { // will override the initial SelectedID setting if true
ctrl.SaveState(ctx, true)
}
if c.OnRowSelected != nil {
ctrl.On(event.RowSelected(), c.OnRowSelected)
}
}
// GetSelectTable is a convenience method to return the button with the given id from the page.
func GetSelectTable(c page.ControlI, id string) *SelectTable {
return c.Page().GetControl(id).(*SelectTable)
}
func init() {
page.RegisterControl(&SelectTable{})
}