From 4f5ed85c1914690e1023f1ae308c9583069f4d57 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Sun, 25 Dec 2016 11:59:33 -0800 Subject: adding error handling and less alloc happy buffer writes in editor code --- management/editor/dom.go | 236 ++++++++++++++++++++++++++++++++++------- management/editor/editor.go | 54 ++++++++-- management/editor/repeaters.go | 66 ++++++++++-- 3 files changed, 297 insertions(+), 59 deletions(-) diff --git a/management/editor/dom.go b/management/editor/dom.go index 7fa2b54..41aafa7 100644 --- a/management/editor/dom.go +++ b/management/editor/dom.go @@ -3,6 +3,7 @@ package editor import ( "bytes" "html" + "log" "strings" ) @@ -29,108 +30,265 @@ func newElement(tagName, label, fieldName string, p interface{}, attrs map[strin // domElementSelfClose is a special DOM element which is parsed as a // self-closing tag and thus needs to be created differently func domElementSelfClose(e *element) []byte { - e.viewBuf.Write([]byte(`
`)) + _, err := e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil + } + if e.label != "" { - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString( + ``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil + } + } + + _, err = e.viewBuf.WriteString(`<` + e.tagName + ` value="`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil + } + + _, err = e.viewBuf.WriteString(html.EscapeString(e.data) + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil } - e.viewBuf.Write([]byte(`<` + e.tagName + ` value="`)) - e.viewBuf.Write([]byte(html.EscapeString(e.data) + `" `)) for attr, value := range e.attrs { - e.viewBuf.Write([]byte(attr + `="` + value + `" `)) + _, err := e.viewBuf.WriteString(attr + `="` + value + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil + } + } + _, err = e.viewBuf.WriteString(` name="` + e.name + `" />`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil + } + + _, err = e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementSelfClose") + return nil } - e.viewBuf.Write([]byte(` name="` + e.name + `"`)) - e.viewBuf.Write([]byte(` />`)) - e.viewBuf.Write([]byte(`
`)) return e.viewBuf.Bytes() } // domElementCheckbox is a special DOM element which is parsed as a // checkbox input tag and thus needs to be created differently func domElementCheckbox(e *element) []byte { - e.viewBuf.Write([]byte(`

`)) - e.viewBuf.Write([]byte(`<` + e.tagName + ` `)) + _, err := e.viewBuf.WriteString(`

`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } + + _, err = e.viewBuf.WriteString(`<` + e.tagName + ` `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } for attr, value := range e.attrs { - e.viewBuf.Write([]byte(attr + `="` + value + `" `)) + _, err := e.viewBuf.WriteString(attr + `="` + value + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } } - e.viewBuf.Write([]byte(` name="` + e.name + `"`)) - e.viewBuf.Write([]byte(` /> `)) + _, err = e.viewBuf.WriteString(` name="` + e.name + `" />`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } + if e.label != "" { - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString( + ``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } } - e.viewBuf.Write([]byte(`

`)) + + _, err = e.viewBuf.WriteString(`

`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementCheckbox") + return nil + } + return e.viewBuf.Bytes() } // domElement creates a DOM element func domElement(e *element) []byte { - e.viewBuf.Write([]byte(`
`)) + _, err := e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } if e.label != "" { - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString( + ``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } + } + + _, err = e.viewBuf.WriteString(`<` + e.tagName + ` `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil } - e.viewBuf.Write([]byte(`<` + e.tagName + ` `)) for attr, value := range e.attrs { - e.viewBuf.Write([]byte(attr + `="` + string(value) + `" `)) + _, err = e.viewBuf.WriteString(attr + `="` + string(value) + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } + } + _, err = e.viewBuf.WriteString(` name="` + e.name + `" > `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil } - e.viewBuf.Write([]byte(` name="` + e.name + `"`)) - e.viewBuf.Write([]byte(` >`)) - e.viewBuf.Write([]byte(html.EscapeString(e.data))) - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString(html.EscapeString(e.data)) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } + + _, err = e.viewBuf.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } + + _, err = e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElement") + return nil + } - e.viewBuf.Write([]byte(`
`)) return e.viewBuf.Bytes() } func domElementWithChildrenSelect(e *element, children []*element) []byte { - e.viewBuf.Write([]byte(`
`)) + _, err := e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil + } - e.viewBuf.Write([]byte(`<` + e.tagName + ` `)) + _, err = e.viewBuf.WriteString(`<` + e.tagName + ` `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil + } for attr, value := range e.attrs { - e.viewBuf.Write([]byte(attr + `="` + string(value) + `" `)) + _, err = e.viewBuf.WriteString(attr + `="` + value + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil + } + } + _, err = e.viewBuf.WriteString(` name="` + e.name + `" >`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil } - e.viewBuf.Write([]byte(` name="` + e.name + `"`)) - e.viewBuf.Write([]byte(` >`)) // loop over children and create domElement for each child for _, child := range children { - e.viewBuf.Write(domElement(child)) + _, err = e.viewBuf.Write(domElement(child)) + if err != nil { + log.Println("Error writing HTML domElement to buffer: domElementWithChildrenSelect") + return nil + } } - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil + } if e.label != "" { - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil + } + } + + _, err = e.viewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenSelect") + return nil } - e.viewBuf.Write([]byte(`
`)) return e.viewBuf.Bytes() } func domElementWithChildrenCheckbox(e *element, children []*element) []byte { - e.viewBuf.Write([]byte(`<` + e.tagName + ` `)) + _, err := e.viewBuf.WriteString(`<` + e.tagName + ` `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenCheckbox") + return nil + } for attr, value := range e.attrs { - e.viewBuf.Write([]byte(attr + `="` + value + `" `)) + _, err = e.viewBuf.WriteString(attr + `="` + value + `" `) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenCheckbox") + return nil + } } - e.viewBuf.Write([]byte(` >`)) + _, err = e.viewBuf.WriteString(` >`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenCheckbox") + return nil + } if e.label != "" { - e.viewBuf.Write([]byte(``)) + _, err = e.viewBuf.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenCheckbox") + return nil + } } // loop over children and create domElement for each child for _, child := range children { - e.viewBuf.Write(domElementCheckbox(child)) + _, err = e.viewBuf.Write(domElementCheckbox(child)) + if err != nil { + log.Println("Error writing HTML domElementCheckbox to buffer: domElementWithChildrenCheckbox") + return nil + } } - e.viewBuf.Write([]byte(`
 
`)) + _, err = e.viewBuf.WriteString(`
 
`) + if err != nil { + log.Println("Error writing HTML string to buffer: domElementWithChildrenCheckbox") + return nil + } return e.viewBuf.Bytes() } diff --git a/management/editor/editor.go b/management/editor/editor.go index 7194c27..511edb2 100644 --- a/management/editor/editor.go +++ b/management/editor/editor.go @@ -4,6 +4,7 @@ package editor import ( "bytes" + "log" "net/http" ) @@ -38,16 +39,28 @@ func Form(post Editable, fields ...Field) ([]byte, error) { editor := post.Editor() editor.ViewBuf = &bytes.Buffer{} - editor.ViewBuf.Write([]byte(`
`)) + _, err := editor.ViewBuf.WriteString(``)) + _, err = editor.ViewBuf.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to editor Form buffer") + return nil, err + } // content items with Item embedded have some default fields we need to render - editor.ViewBuf.Write([]byte(`
`) + if err != nil { + log.Println("Error writing HTML string to editor Form buffer") + return nil, err + } for _, f := range fields { addFieldToEditorView(editor, f) } - editor.ViewBuf.Write([]byte(`
`)) + _, err = editor.ViewBuf.WriteString(`
`) + if err != nil { + log.Println("Error writing HTML string to editor Form buffer") + return nil, err + } publishTime := `
@@ -98,9 +111,16 @@ func Form(post Editable, fields ...Field) ([]byte, error) {
` - editor.ViewBuf.Write([]byte(publishTime)) + _, err = editor.ViewBuf.WriteString(publishTime) + if err != nil { + log.Println("Error writing HTML string to editor Form buffer") + return nil, err + } - addPostDefaultFieldsToEditorView(post, editor) + err = addPostDefaultFieldsToEditorView(post, editor) + if err != nil { + return nil, err + } submit := `
@@ -186,16 +206,26 @@ func Form(post Editable, fields ...Field) ([]byte, error) { }); ` - editor.ViewBuf.Write([]byte(submit + script + `
`)) + _, err = editor.ViewBuf.WriteString(submit + script + `
`) + if err != nil { + log.Println("Error writing HTML string to editor Form buffer") + return nil, err + } return editor.ViewBuf.Bytes(), nil } -func addFieldToEditorView(e *Editor, f Field) { - e.ViewBuf.Write(f.View) +func addFieldToEditorView(e *Editor, f Field) error { + _, err := e.ViewBuf.Write(f.View) + if err != nil { + log.Println("Error writing field view to editor view buffer") + return err + } + + return nil } -func addPostDefaultFieldsToEditorView(p Editable, e *Editor) { +func addPostDefaultFieldsToEditorView(p Editable, e *Editor) error { defaults := []Field{ Field{ View: Input("Slug", p, map[string]string{ @@ -220,7 +250,11 @@ func addPostDefaultFieldsToEditorView(p Editable, e *Editor) { } for _, f := range defaults { - addFieldToEditorView(e, f) + err := addFieldToEditorView(e, f) + if err != nil { + return err + } } + return nil } diff --git a/management/editor/repeaters.go b/management/editor/repeaters.go index f9a289c..4a597c5 100644 --- a/management/editor/repeaters.go +++ b/management/editor/repeaters.go @@ -3,6 +3,7 @@ package editor import ( "bytes" "fmt" + "log" "strings" ) @@ -39,7 +40,12 @@ func InputRepeater(fieldName string, p interface{}, attrs map[string]string) []b scope := tagNameFromStructField(fieldName, p) html := bytes.Buffer{} - html.WriteString(``) + _, err := html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to InputRepeater buffer") + return nil + } + for i, val := range vals { el := &element{ tagName: "input", @@ -54,9 +60,17 @@ func InputRepeater(fieldName string, p interface{}, attrs map[string]string) []b el.label = attrs["label"] } - html.Write(domElementSelfClose(el)) + _, err := html.Write(domElementSelfClose(el)) + if err != nil { + log.Println("Error writing domElementSelfClose to InputRepeater buffer") + return nil + } + } + _, err := html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to InputRepeater buffer") + return nil } - html.WriteString(``) return append(html.Bytes(), RepeatController(fieldName, p, "input", ".input-field")...) } @@ -72,7 +86,11 @@ func SelectRepeater(fieldName string, p interface{}, attrs, options map[string]s // scope := tagNameFromStructField(fieldName, p) html := bytes.Buffer{} - html.WriteString(``) + _, err := html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to SelectRepeater buffer") + return nil + } // find the field values in p to determine if an option is pre-selected fieldVals := valueFromStructField(fieldName, p) @@ -131,11 +149,20 @@ func SelectRepeater(fieldName string, p interface{}, attrs, options map[string]s opts = append(opts, opt) } - html.Write(domElementWithChildrenSelect(sel, opts)) + _, err := html.Write(domElementWithChildrenSelect(sel, opts)) + if err != nil { + log.Println("Error writing domElementWithChildrenSelect to SelectRepeater buffer") + return nil + } } } - html.WriteString(``) + _, err = html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to SelectRepeater buffer") + return nil + } + return append(html.Bytes(), RepeatController(fieldName, p, "select", ".input-field")...) } @@ -227,14 +254,33 @@ func FileRepeater(fieldName string, p interface{}, attrs map[string]string) []by name := tagNameFromStructField(fieldName, p) html := bytes.Buffer{} - html.WriteString(``) + _, err := html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to FileRepeater buffer") + return nil + } + for i, val := range vals { className := fmt.Sprintf("%s-%d", name, i) nameidx := tagNameFromStructFieldMulti(fieldName, i, p) - html.WriteString(fmt.Sprintf(tmpl, nameidx, addLabelFirst(i, attrs["label"]), val, className, fieldName)) - html.WriteString(fmt.Sprintf(script, nameidx, className)) + + _, err := html.WriteString(fmt.Sprintf(tmpl, nameidx, addLabelFirst(i, attrs["label"]), val, className, fieldName)) + if err != nil { + log.Println("Error writing HTML string to FileRepeater buffer") + return nil + } + + _, err = html.WriteString(fmt.Sprintf(script, nameidx, className)) + if err != nil { + log.Println("Error writing HTML string to FileRepeater buffer") + return nil + } + } + _, err = html.WriteString(``) + if err != nil { + log.Println("Error writing HTML string to FileRepeater buffer") + return nil } - html.WriteString(``) return append(html.Bytes(), RepeatController(fieldName, p, "input.upload", "div.file-input."+fieldName)...) } -- cgit v1.2.3