1 // Package xform provides some shortcut funcs for various form related activites 2 package xform // import "vimagination.zapto.org/gopherjs/xform" 3 4 import ( 5 "strconv" 6 7 "github.com/gopherjs/gopherjs/js" 8 "honnef.co/go/js/dom" 9 "vimagination.zapto.org/gopherjs/style" 10 "vimagination.zapto.org/gopherjs/xdom" 11 ) 12 13 func init() { 14 style.Add(`label { 15 display : block; 16 float : left; 17 text-align : right; 18 width : 200px; 19 } 20 21 label:after { 22 content : ':'; 23 } 24 25 .sizeableInput { 26 border : 2px inset #DCDAD5; 27 padding-left : 3px; 28 padding-right : 3px; 29 min-width : 50px; 30 height : 20px; 31 margin-top : 2px; 32 } 33 `) 34 } 35 36 // InputSizeable returns a content-editable span that is style to look a text 37 // input box 38 func InputSizeable(id, value string) *dom.HTMLSpanElement { 39 s := xdom.Span() 40 s.Class().SetString("sizeableInput") 41 s.SetContentEditable("true") 42 s.Set("spellcheck", "false") 43 if id != "" { 44 s.SetID(id) 45 } 46 s.Underlying().Call("appendChild", js.Global.Get("document").Call("createTextNode", value)) 47 return s 48 } 49 50 // SizeableList is a collection of InputSizable elements 51 type SizeableList struct { 52 *dom.HTMLDivElement 53 contents []*dom.HTMLSpanElement 54 } 55 56 // InputSizeableList creates a list of InputSizeable elements, wrapped in a div 57 func InputSizeableList(values ...string) *SizeableList { 58 d := xdom.Div() 59 d.Class().SetString("sizeableList") 60 contents := make([]*dom.HTMLSpanElement, len(values)) 61 for i, value := range values { 62 s := InputSizeable("", value) 63 d.AppendChild(s) 64 contents[i] = s 65 } 66 sl := &SizeableList{ 67 d, 68 contents, 69 } 70 remove := InputButton("", "-") 71 remove.AddEventListener("click", false, func(dom.Event) { 72 l := len(sl.contents) - 1 73 d.RemoveChild(sl.contents[l]) 74 sl.contents = sl.contents[:l] 75 }) 76 add := InputButton("", "+") 77 add.AddEventListener("click", false, func(dom.Event) { 78 s := InputSizeable("", "") 79 d.InsertBefore(s, remove) 80 sl.contents = append(sl.contents, s) 81 }) 82 d.AppendChild(remove) 83 d.AppendChild(add) 84 return sl 85 } 86 87 // Values returns the values of the enclose InputSizeable's 88 func (s *SizeableList) Values() []string { 89 v := make([]string, len(s.contents)) 90 for i, s := range s.contents { 91 v[i] = s.TextContent() 92 } 93 return v 94 } 95 96 // Label create a form label 97 func Label(label, forID string) *dom.HTMLLabelElement { 98 l := xdom.Label() 99 l.For = forID 100 l.Underlying().Call("appendChild", js.Global.Get("document").Call("createTextNode", label)) 101 return l 102 } 103 104 // InputText creates a text input box 105 func InputText(id, value string) *dom.HTMLInputElement { 106 i := xdom.Input() 107 i.Type = "text" 108 if id != "" { 109 i.SetID(id) 110 } 111 i.Value = value 112 return i 113 } 114 115 // InputCheckbox creates a checkbox input 116 func InputCheckbox(id string, value bool) *dom.HTMLInputElement { 117 i := xdom.Input() 118 i.Type = "checkbox" 119 if id != "" { 120 i.SetID(id) 121 } 122 i.Checked = value 123 return i 124 } 125 126 // InputRadio create a radio button input 127 func InputRadio(id, name string, value bool) *dom.HTMLInputElement { 128 i := xdom.Input() 129 i.Type = "radio" 130 i.Name = name 131 if id != "" { 132 i.SetID(id) 133 } 134 i.Checked = value 135 return i 136 } 137 138 // InputUpload creates an upload input field 139 func InputUpload(id string) *dom.HTMLInputElement { 140 i := xdom.Input() 141 i.Type = "file" 142 if id != "" { 143 i.SetID(id) 144 } 145 return i 146 } 147 148 // InputButton creates a button input 149 func InputButton(id, name string) *dom.HTMLInputElement { 150 i := xdom.Input() 151 i.Type = "button" 152 i.Value = name 153 if id != "" { 154 i.SetID(id) 155 } 156 return i 157 } 158 159 // InputSubmit creates a submit input 160 func InputSubmit(name string) *dom.HTMLInputElement { 161 i := xdom.Input() 162 i.Type = "submit" 163 i.Value = name 164 return i 165 } 166 167 // InputPassword creates a password input 168 func InputPassword(id, value string) *dom.HTMLInputElement { 169 i := xdom.Input() 170 i.Type = "password" 171 i.Value = value 172 if id != "" { 173 i.SetID(id) 174 } 175 return i 176 } 177 178 // InputNumber creates a text input that only allows number to be entered 179 func InputNumber(id string, min, max, value float64) *dom.HTMLInputElement { 180 i := xdom.Input() 181 i.Type = "number" 182 i.Min = strconv.FormatFloat(min, 'f', -1, 64) 183 i.Max = strconv.FormatFloat(max, 'f', -1, 64) 184 i.ValueAsNumber = value 185 if id != "" { 186 i.SetID(id) 187 } 188 return i 189 } 190 191 // InputDate create a date based input, the workings of which are implementation 192 // specific 193 func InputDate(id string) *dom.HTMLInputElement { 194 i := xdom.Input() 195 i.Type = "date" 196 if id != "" { 197 i.SetID(id) 198 } 199 return i 200 } 201 202 // InputDateTime create a datetime based input, the workings of which are 203 // implementation specific 204 func InputDateTime(id string) *dom.HTMLInputElement { 205 i := xdom.Input() 206 i.Type = "datetime" 207 if id != "" { 208 i.SetID(id) 209 } 210 return i 211 } 212 213 // InputDateTimeLocal create a local datetime based input, the workings of 214 // which are implementation specific 215 func InputDateTimeLocal(id string) *dom.HTMLInputElement { 216 i := xdom.Input() 217 i.Type = "datetime-local" 218 if id != "" { 219 i.SetID(id) 220 } 221 return i 222 } 223 224 // InputMonth creates a month based input box 225 func InputMonth(id string) *dom.HTMLInputElement { 226 i := xdom.Input() 227 i.Type = "month" 228 if id != "" { 229 i.SetID(id) 230 } 231 return i 232 } 233 234 // InputWeek creates a week based input box 235 func InputWeek(id string) *dom.HTMLInputElement { 236 i := xdom.Input() 237 i.Type = "week" 238 if id != "" { 239 i.SetID(id) 240 } 241 return i 242 } 243 244 // InputTime creates a time based input box 245 func InputTime(id string) *dom.HTMLInputElement { 246 i := xdom.Input() 247 i.Type = "time" 248 if id != "" { 249 i.SetID(id) 250 } 251 return i 252 } 253 254 // InputColor creates a colour based input box, the workings of which are 255 // implementation specific 256 func InputColor(id string) *dom.HTMLInputElement { 257 i := xdom.Input() 258 i.Type = "color" 259 if id != "" { 260 i.SetID(id) 261 } 262 return i 263 } 264 265 // InputRange creates a sliding rule with which a number in the given range 266 // can be selected 267 func InputRange(id string, min, max, step, value float64) *dom.HTMLInputElement { 268 i := xdom.Input() 269 i.Type = "range" 270 i.Min = strconv.FormatFloat(min, 'f', -1, 64) 271 i.Max = strconv.FormatFloat(max, 'f', -1, 64) 272 i.Value = strconv.FormatFloat(value, 'f', -1, 64) 273 if step != step { 274 i.Step = "all" 275 } else { 276 i.Step = strconv.FormatFloat(min, 'f', -1, 64) 277 } 278 if id != "" { 279 i.SetID(id) 280 } 281 return i 282 } 283 284 // InputEmail is a text box that validates as an email address 285 func InputEmail(id, value string) *dom.HTMLInputElement { 286 i := xdom.Input() 287 i.Type = "email" 288 i.Value = value 289 if id != "" { 290 i.SetID(id) 291 } 292 return i 293 } 294 295 // InputURL is a text box that validates as a URL 296 func InputURL(id, value string) *dom.HTMLInputElement { 297 i := xdom.Input() 298 i.Type = "url" 299 i.Value = value 300 if id != "" { 301 i.SetID(id) 302 } 303 return i 304 } 305 306 // Option is a structure to define a 'select's option. 307 type Option struct { 308 Label, Value string 309 Selected bool 310 } 311 312 // SelectBox provides a select input, filled with the given options 313 func SelectBox(id string, values ...Option) *dom.HTMLSelectElement { 314 s := xdom.Select() 315 if id != "" { 316 s.SetID(id) 317 } 318 selected := false 319 su := s.Underlying() 320 for _, v := range values { 321 o := xdom.Option() 322 o.Value = v.Value 323 if v.Selected && !selected { 324 selected = true 325 o.Selected = true 326 } 327 o.Underlying().Call("appendChild", js.Global.Get("document").Call("createTextNode", v.Label)) 328 su.Call("appendChild", o.Underlying()) 329 } 330 return s 331 } 332 333 // TextArea provides a textarea input 334 func TextArea(id string, value string) *dom.HTMLTextAreaElement { 335 t := xdom.Textarea() 336 if id != "" { 337 t.SetID(id) 338 } 339 t.Underlying().Call("appendChild", js.Global.Get("document").Call("createTextNode", value)) 340 return t 341 }