Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 62 additions & 14 deletions form/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
)

var Header string = `
var Header = `

function addChildNode(ev) {
ev.preventDefault();
Expand Down Expand Up @@ -166,6 +166,9 @@ function replaceAll(str, search, replace) {
function getFields(node) {
var nodeJson = {};
$("> div.field > div ", $(node)).each(function(idx, field) {
if($(field.parentNode).hasClass('oneof-disabled')) {
return
}
$("> input[type=text]", $(field)).each(function(idx, input) {
nodeJson[$(input).attr("name")] = replaceAll($(input).val(), "&", "%26");
});
Expand Down Expand Up @@ -196,6 +199,9 @@ function getFields(node) {
});
});
$("> div.fields > div ", $(node)).each(function(idx, field) {
if($(field).hasClass('oneof-disabled')) {
return
}
$("input[type=text]", $(field)).each(function(idx, input) {
var fieldname = $(input).attr("name");
if (!(fieldname in nodeJson)) {
Expand Down Expand Up @@ -403,6 +409,17 @@ function setRepStrValue(value) {
return "value=" + JSON.stringify(HTMLEncode(decode_utf8(value)));
}

function oneofSelect(selected, oneofSelector) {
$("> div.field."+oneofSelector, selected.parentNode).addClass('oneof-disabled');
$(selected).removeClass('oneof-disabled');
}

function oneofDisabled(value) {
if(value == undefined || value == null) {
return "oneof-disabled";
}
}

`

func isBool(f *descriptor.FieldDescriptorProto) bool {
Expand Down Expand Up @@ -502,6 +519,21 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
tooltip = ` <a href="#" data-toggle="tooltip" title="` + strings.Replace(help, "\n", " ", -1) + `"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span></a>`
colon = ""
}

var oneofClass string
var oneofClick string
if f.OneofIndex != nil {
oneofClass += fmt.Sprintf("oneof-%d '+oneofDisabled(json['"+f.GetName()+"'])+'", *f.OneofIndex)
if *f.OneofIndex%2 == 0 {
oneofClass += " oneof-even"
} else {
oneofClass += " oneof-odd"
}

action := fmt.Sprintf(`oneofSelect(this, \'oneof-%d\')`, *f.OneofIndex)
oneofClick += `onClick="` + action + `" onFocusIn="` + action + `" onChange="` + action + `"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could educate me here, but why is onClick, onFocusIn and onChange all necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that just onClick wasn't working when selecting the existing value (drag-select). The OnFocusIn and onChange (typing) fix that.

}

fieldname := f.GetName()
if f.IsMessage() {
typName := typ(fieldname, f.IsRepeated(), getMessage(f, fileDescriptorSet))
Expand Down Expand Up @@ -531,7 +563,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
if f.DefaultValue != nil {
defaultBool = f.GetDefaultValue()
}
s := `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label>';
s := `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label>';
`
s += `s += '<div class="col-sm-10"><div class="btn-group" data-toggle="buttons">';
`
Expand All @@ -557,7 +589,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
}
}
if len(enum.GetValue()) <= 4 {
s := `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label>';
s := `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label>';
`
s += `s += '<div class="col-sm-10"><div class="btn-group" data-toggle="buttons">';
`
Expand All @@ -571,7 +603,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
`
return s
} else {
s := `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10">';
s := `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10">';
s += '<select class="form-control" name="` + fieldname + `">';
`
for _, v := range enum.GetValue() {
Expand All @@ -591,7 +623,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
if f.DefaultValue != nil {
def = f.GetDefaultValue()
}
return `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="number" step="1" '+setValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
return `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="number" step="1" '+setValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
`
} else if isFloat(f) {
def := "\"\""
Expand All @@ -601,7 +633,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
if f.DefaultValue != nil {
def = f.GetDefaultValue()
}
return `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="number" step="any" '+setValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
return `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="number" step="any" '+setValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
`
} else {
def := "undefined"
Expand All @@ -611,7 +643,7 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
if f.DefaultValue != nil {
def = strconv.Quote(f.GetDefaultValue())
}
return `s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="text" '+setStrValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
return `s += '<div class="field form-group ` + oneofClass + `" ` + oneofClick + `><label class="col-sm-2 control-label">` + fieldname + tooltip + colon + ` </label><div class="col-sm-10"><input class="form-control" name="` + f.GetName() + `" type="text" '+setStrValue(` + def + `, json["` + f.GetName() + `"])+'/></div></div>';
`
}
} else {
Expand All @@ -628,8 +660,8 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
`
return s
} else if isNumber(f) || isEnum(f) {
s :=
`s += '<div class="fields" fieldname="` + fieldname + `">';
s := `
s += '<div class="fields" fieldname="` + fieldname + `">';
var ` + fieldname + ` = getList(json, "` + fieldname + `");
for (var i = 0; i < ` + fieldname + `.length; i++) {
s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + `: </label><div class="col-sm-8"><input class="form-control" name="` + fieldname + `" type="number" step="any" repeated="true" '+setRepValue(json["` + f.GetName() + `"][i])+'/></div><div class="col-sm-2"><a href="#" class="del-field btn btn-warning btn-sm" role="button">Remove</a></div></div>';
Expand All @@ -640,8 +672,8 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
`
return s
} else if isFloat(f) {
s :=
`s += '<div class="fields" fieldname="` + fieldname + `">';
s := `
s += '<div class="fields" fieldname="` + fieldname + `">';
var ` + fieldname + ` = getList(json, "` + fieldname + `");
for (var i = 0; i < ` + fieldname + `.length; i++) {
s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + `: </label><div class="col-sm-8"><input class="form-control" name="` + fieldname + `" type="number" step="1" repeated="true" '+setRepValue(json["` + f.GetName() + `"][i])+'/></div><div class="col-sm-2"><a href="#" class="del-field btn btn-warning btn-sm" role="button">Remove</a></div></div>';
Expand All @@ -652,8 +684,8 @@ func BuildField(fileDescriptorSet *descriptor.FileDescriptorSet, msg *descriptor
`
return s
} else {
s :=
`s += '<div class="fields" fieldname="` + fieldname + `">';
s := `
s += '<div class="fields" fieldname="` + fieldname + `">';
var ` + fieldname + ` = getList(json, "` + fieldname + `");
for (var i = 0; i < ` + fieldname + `.length; i++) {
s += '<div class="field form-group"><label class="col-sm-2 control-label">` + fieldname + `: </label><div class="col-sm-8"><input class="form-control" name="` + fieldname + `" type="text" repeated="true" '+setRepStrValue(json["` + f.GetName() + `"][i])+'/></div><div class="col-sm-2"><a href="#" class="del-field btn btn-warning btn-sm" role="button">Remove</a></div></div>';
Expand Down Expand Up @@ -685,6 +717,9 @@ func Builder(visited map[string]struct{}, root bool, fieldname string, help stri
s = append(s, `s += '<a href="#" class="del-child btn btn-danger btn-xs" role="button" fieldname="`+fieldname+`">Remove</a>'`)
s = append(s, `s += '</div><div class="col-sm-10">'`)
s = append(s, `s += '<label class="heading">`+fieldname+`</label>'`)
if len(msg.OneofDecl) > 0 {
s = append(s, `s += '<br/>This message has `+fmt.Sprintf("%d", len(msg.OneofDecl))+` oneof declarations.<br/>'`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is just for debugging, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I wanted to include an explanation. But maybe it's better to put some time in the layout itself so the user can easily identify which oneof fields belong together.

}
s = append(s, `s += '</div></div>'`)
}
ms := []string{}
Expand Down Expand Up @@ -782,13 +817,26 @@ func CreateCustom(methodName, packageName, messageName string, g *generator.Gene
}

label{
font-weight: normal;
font-weight: normal;
}

.heading {
font-weight: bold;
}

.oneof-disabled {
color: grey;
}
.oneof-disabled input {
background-color: grey;
}
.oneof-even > div {
border-right: 5px solid red;
}
.oneof-odd > div {
border-right: 5px solid blue;
}

</style>
`
return text
Expand Down
5 changes: 3 additions & 2 deletions html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (p *html) generateFormFunc(servName string, method *descriptor.MethodDescri
<h3>` + servName + `: ` + method.GetName() + `</h3>
` + form.Create(method.GetName(), packageName, messageName, p.Generator) + `
</div>`
p.P(`var Form`, servName, "_", method.GetName(), " string = `", s, "`")
p.P(`var Form`, servName, "_", method.GetName(), " = `", s, "`")
}

func (p *html) Generate(file *generator.FileDescriptor) {
Expand All @@ -109,6 +109,7 @@ func (p *html) Generate(file *generator.FileDescriptor) {
p.strconvPkg = p.NewImport("strconv")
logPkg := p.NewImport("log")
grpcPkg := p.NewImport("google.golang.org/grpc")
jsonpbPkg := p.NewImport("github.com/golang/protobuf/jsonpb")

p.P(`var DefaultHtmlStringer = func(req, resp interface{}) ([]byte, error) {`)
p.In()
Expand Down Expand Up @@ -177,7 +178,7 @@ func (p *html) Generate(file *generator.FileDescriptor) {
p.P(`msg := &`, p.typeName(m.GetInputType()), `{}`)
p.P(`if len(jsonString) > 0 {`)
p.In()
p.P(`err := `, p.jsonPkg.Use(), `.Unmarshal([]byte(jsonString), msg)`)
p.P(`err := `, jsonpbPkg.Use(), `.UnmarshalString(jsonString, msg)`)
p.writeError(errString)
p.P(`someValue = true`)
p.Out()
Expand Down
91 changes: 88 additions & 3 deletions letmetestserver/serve/serve.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion letmetestserver/serve/serve.proto
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ message EndLess {
}

message Tree {
string Value = 1;
oneof stuff {
string ValueString = 1;
uint64 ValueNum = 4;
}
Tree Left = 2;
Tree Right = 3;
}
Expand Down
Loading