-
Notifications
You must be signed in to change notification settings - Fork 5
/
select.go
123 lines (111 loc) · 3.24 KB
/
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
/*******************************************************************************
*
* Copyright 2019 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*******************************************************************************/
package h
import (
"encoding/hex"
"fmt"
"html/template"
math_rand "math/rand"
"net/http"
)
//SelectFieldSpec is a FormField where values can be selected from a given set.
//It's rendered as a series of checkboxes.
type SelectFieldSpec struct {
Name string
Label string
Options []SelectOptionSpec
ReadOnly bool
}
//ReadState implements the FormField interface.
func (f SelectFieldSpec) ReadState(r *http.Request, formState *FormState) {
if f.ReadOnly {
return
}
isValidValue := make(map[string]bool)
for _, o := range f.Options {
isValidValue[o.Value] = true
}
s := FieldState{Selected: make(map[string]bool)}
for _, value := range r.PostForm[f.Name] {
s.Selected[value] = true
if !isValidValue[value] {
s.ErrorMessage = fmt.Sprintf("does not have the option %q", value)
}
}
formState.Fields[f.Name] = &s
}
var selectFieldSnippetReadonly = NewSnippet(`
<div class="form-row">
<div class="row-label">{{.Spec.Label}}</div>
<div class="item-list item-list-readonly">
{{range .Spec.Options}}
{{ $unchecked := not (index $.State.Selected .Value) }}
<span class="item item-{{if $unchecked}}un{{end}}checked">{{.Label}}</span>
{{end}}
</div>
</div>
`)
var selectFieldSnippet = NewSnippet(`
<div class="form-row">
<div class="row-label">
{{.Spec.Label}}
{{if .State.ErrorMessage}}
<span class="form-error">{{.State.ErrorMessage}}</span>
{{end}}
</div>
<div class="item-list">
{{- range $idx, $opt := .Spec.Options -}}
{{- $id := printf "%s-%d" $.Spec.Name $idx -}}
<input
type="checkbox"
name="{{$.Spec.Name}}"
id="{{$id}}"
value="{{$opt.Value}}"
{{if index $.State.Selected $opt.Value}}checked{{end}}
/><label for="{{$id}}" class="item">{{$opt.Label}}</label>
{{- end -}}
</div>
</div>
`)
//RenderField implements the FormField interface.
func (f SelectFieldSpec) RenderField(state FormState) template.HTML {
data := struct {
Spec SelectFieldSpec
State *FieldState
}{
Spec: f,
State: state.Fields[f.Name],
}
if data.State == nil {
data.State = &FieldState{}
}
if f.ReadOnly {
return selectFieldSnippetReadonly.Render(data)
}
return selectFieldSnippet.Render(data)
}
//SelectOptionSpec describes an option that can be selected in a SelectFieldSpec.
type SelectOptionSpec struct {
Value string
Label string
}
func getRandomID() string {
var buf [10]byte
math_rand.Read(buf[:])
return hex.EncodeToString(buf[:])
}