Initial commit
This commit is contained in:
commit
c672ec1666
110
serializer.js
Normal file
110
serializer.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
class SerializerField {
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} f Input field (input|select|textarea)
|
||||||
|
* @returns {SerializerField}
|
||||||
|
*/
|
||||||
|
constructor(f){
|
||||||
|
this.field = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* serialize
|
||||||
|
*
|
||||||
|
* @returns {(String|Number)}
|
||||||
|
*/
|
||||||
|
serialize(){
|
||||||
|
let type = this.field.getAttribute("type");
|
||||||
|
if(type == "number" || type == "range"){
|
||||||
|
return Number(this.field.value);
|
||||||
|
} else if(type == "date" || type == "datetime-local" || type == "month" || type == "week") {
|
||||||
|
return new Date(this.field.value);
|
||||||
|
} else {
|
||||||
|
return this.field.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Serializer {
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @returns {Serializer}
|
||||||
|
*/
|
||||||
|
constructor(element){
|
||||||
|
let fields = element.querySelectorAll(`:scope > input:not([type="submit"]), :scope > select, :scope > textarea, :scope > group`);
|
||||||
|
|
||||||
|
this._fields = new Map();
|
||||||
|
|
||||||
|
for(let f of fields){
|
||||||
|
this.addField(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addField
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} f
|
||||||
|
*/
|
||||||
|
addField(f){
|
||||||
|
let fieldName = f.getAttribute("name");
|
||||||
|
let isArray = fieldName.match(/^\[(\d*)\]/)
|
||||||
|
|
||||||
|
let field;
|
||||||
|
if(f.tagName == "GROUP"){
|
||||||
|
field = new Serializer(f)
|
||||||
|
} else {
|
||||||
|
field = new SerializerField(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isArray){
|
||||||
|
fieldName = fieldName.replace(/^\[(\d*)\]/, '');
|
||||||
|
if(!this._fields.has(fieldName)){
|
||||||
|
this._fields.set(fieldName, [])
|
||||||
|
}
|
||||||
|
if(isArray[1] != ""){
|
||||||
|
this._fields.get(fieldName)[isArray[1]] = field
|
||||||
|
} else {
|
||||||
|
this._fields.get(fieldName).push(field)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._fields.set(fieldName, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* serialize
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
serialize(){
|
||||||
|
let json = {};
|
||||||
|
for(let [k, f] of this._fields){
|
||||||
|
if(Array.isArray(f)){
|
||||||
|
if(k != ""){
|
||||||
|
json[k] = [];
|
||||||
|
} else {
|
||||||
|
json = [];
|
||||||
|
}
|
||||||
|
for(let key in f){
|
||||||
|
if(f[key]){
|
||||||
|
if(k == ""){
|
||||||
|
json[key] = f[key].serialize()
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
json[k][key] = f[key].serialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(k == ""){
|
||||||
|
json = f.serialize()
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
json[k] = f.serialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
133
tests/main.go
Normal file
133
tests/main.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
|
"text/tabwriter"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var templates *template.Template
|
||||||
|
var tw *tabwriter.Writer
|
||||||
|
var testData = []*Person{
|
||||||
|
&Person{
|
||||||
|
Name: "Foo",
|
||||||
|
Surname: "Bar",
|
||||||
|
Age: 57,
|
||||||
|
BirthDate: time.Date(1960, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
&Person{
|
||||||
|
Name: "Crow",
|
||||||
|
Surname: "CrowCrow",
|
||||||
|
Age: 22,
|
||||||
|
BirthDate: time.Date(1995, 1, 5, 0, 0, 0, 0, time.UTC),
|
||||||
|
Languages: []Language{
|
||||||
|
Language{
|
||||||
|
Language: "Dutch",
|
||||||
|
SkillLevel: 9.99,
|
||||||
|
},
|
||||||
|
Language{
|
||||||
|
Language: "English",
|
||||||
|
SkillLevel: 8.4,
|
||||||
|
},
|
||||||
|
Language{
|
||||||
|
Language: "Marokaans",
|
||||||
|
SkillLevel: -9000.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
router := httprouter.New()
|
||||||
|
|
||||||
|
router.GET("/", getTest)
|
||||||
|
router.POST("/", postTest)
|
||||||
|
|
||||||
|
router.ServeFiles("/static/*filepath", http.Dir("../"))
|
||||||
|
|
||||||
|
var err error
|
||||||
|
templates, err = template.ParseGlob(`templates/*.gohtml`)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tw = tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||||
|
|
||||||
|
server := httptest.NewServer(router)
|
||||||
|
|
||||||
|
exec.Command("chromium", "--headless", "--disable-gpu", server.URL).Run()
|
||||||
|
// TODO: Fix closing FF
|
||||||
|
exec.Command("firefox", "-headless", server.URL).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Person ...
|
||||||
|
type Person struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Surname string `json:"surname"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
BirthDate time.Time `json:"birth_date"`
|
||||||
|
Languages []Language `json:"languages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Languages ...
|
||||||
|
type Language struct {
|
||||||
|
Language string `json:"language"`
|
||||||
|
SkillLevel float64 `json:"skill_level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
templates.ExecuteTemplate(w, `test.gohtml`, testData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func postTest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
body, _ := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
|
var p []*Person
|
||||||
|
|
||||||
|
err := json.Unmarshal(body, &p)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
fmt.Println("Person could not be decoded")
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range p {
|
||||||
|
if p[k] == nil && testData[k] == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isEq(*p[k], *testData[k])
|
||||||
|
}
|
||||||
|
tw.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEq(p1, p2 Person) {
|
||||||
|
assert(p1.Name, p2.Name, "Name")
|
||||||
|
assert(p1.Surname, p2.Surname, "Surname")
|
||||||
|
assert(p1.Age, p2.Age, "Age")
|
||||||
|
assert(p1.BirthDate, p2.BirthDate, "BirthDate")
|
||||||
|
for k := range p1.Languages {
|
||||||
|
assert(p1.Languages[k].Language, p2.Languages[k].Language, "Languages.Language")
|
||||||
|
assert(p1.Languages[k].SkillLevel, p2.Languages[k].SkillLevel, "Languages.SkillLevel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assert(v, v2 interface{}, ident string) {
|
||||||
|
if !reflect.DeepEqual(v, v2) {
|
||||||
|
fmt.Fprint(tw, color.RedString("FAIL\t"))
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(tw, color.GreenString("PASS\t"))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(tw, "%s\t%s\n", color.BlueString(ident), color.YellowString(fmt.Sprintf("'%v'\t'%v'", v, v2)))
|
||||||
|
}
|
52
tests/templates/test.gohtml
Normal file
52
tests/templates/test.gohtml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>test</title>
|
||||||
|
<style>
|
||||||
|
form > group{
|
||||||
|
margin: 10px 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
group * {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="/static/serializer.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form id="testform">
|
||||||
|
{{ range $k, $p := . }}
|
||||||
|
{{ if $p }}
|
||||||
|
<group name="[{{ $k }}]">
|
||||||
|
<input name="name" type="text" value="{{ $p.Name }}">
|
||||||
|
<input name="surname" type="text" value="{{ $p.Surname }}">
|
||||||
|
<input name="age" type="number" value="{{ $p.Age }}">
|
||||||
|
<input name="birth_date" type="date" value="{{ $p.BirthDate.Format "2006-01-02" }}">
|
||||||
|
{{ range $p.Languages }}
|
||||||
|
<group name="[]languages">
|
||||||
|
<input name="language" type="text" value="{{ .Language }}">
|
||||||
|
<input name="skill_level" type="number" value="{{ .SkillLevel }}">
|
||||||
|
</group>
|
||||||
|
{{ end }}
|
||||||
|
</group>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
let f = document.getElementById("testform"),
|
||||||
|
s = new Serializer(f);
|
||||||
|
|
||||||
|
fetch("/", {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(s.serialize())
|
||||||
|
}).then(() => {
|
||||||
|
window.close()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user