package form import ( "encoding/json" "strings" ) // Element represents an element that may be added to a Form. Any of the types in this package that implement // the element interface may be used as struct fields when passing the form structure to form.New(). type Element interface { json.Marshaler elem() } // MenuElement represents an element that may be added to a Menu form. This includes buttons, dividers, // headers, and labels. type MenuElement interface { json.Marshaler menuElem() } // Divider represents a visual separator element on a form. It displays a horizontal line. type Divider struct{} // MarshalJSON ... func (d Divider) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]any{ "type": "divider", "text": "", }) } // Header represents a header element on a form. It displays larger, emphasised text for section titles. type Header struct { // Text is the text held by the header. The text may contain Minecraft formatting codes. Text string } // NewHeader creates and returns a new Header with the text passed. func NewHeader(text string) Header { return Header{Text: text} } // MarshalJSON ... func (h Header) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]any{ "type": "header", "text": h.Text, }) } // Label represents a static label on a form. It serves only to display a box of text, and users cannot // submit values to it. type Label struct { // Text is the text held by the label. The text may contain Minecraft formatting codes. Text string } // NewLabel creates and returns a new Label with the values passed. func NewLabel(text string) Label { return Label{Text: text} } // MarshalJSON ... func (l Label) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]any{ "type": "label", "text": l.Text, }) } // Input represents a text input box element. Submitters may write any text in these boxes with no specific // length. type Input struct { // Text is the text displayed over the input element. The text may contain Minecraft formatting codes. Text string // Default is the default value filled out in the input. The user may remove this value and fill out its // own text. The text may contain Minecraft formatting codes. Default string // Placeholder is the text displayed in the input box if it does not contain any text filled out by the // user. The text may contain Minecraft formatting codes. Placeholder string // Tooltip is an optional text displayed when hovering over the element's info icon. The icon only // appears when a tooltip is set. Tooltip string value string } // NewInput creates and returns a new Input with the values passed. func NewInput(text, defaultValue, placeholder string) Input { return Input{Text: text, Default: defaultValue, Placeholder: placeholder} } // WithTooltip returns a copy of the Input with the tooltip set. func (i Input) WithTooltip(tooltip string) Input { i.Tooltip = tooltip return i } // MarshalJSON ... func (i Input) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "input", "text": i.Text, "default": i.Default, "placeholder": i.Placeholder, } if i.Tooltip != "" { m["tooltip"] = i.Tooltip } return json.Marshal(m) } // Value returns the value filled out by the user. func (i Input) Value() string { return i.value } // Toggle represents an on-off button element. Submitters may either toggle this on or off, which will then // hold a value of true or false respectively. type Toggle struct { // Text is the text displayed over the toggle element. The text may contain Minecraft formatting codes. Text string // Default determines if the toggle should be on/off by default. Default bool // Tooltip is an optional text displayed when hovering over the element's info icon. The icon only // appears when a tooltip is set. Tooltip string value bool } // NewToggle creates and returns a new Toggle with the values passed. func NewToggle(text string, defaultValue bool) Toggle { return Toggle{Text: text, Default: defaultValue} } // WithTooltip returns a copy of the Toggle with the tooltip set. func (t Toggle) WithTooltip(tooltip string) Toggle { t.Tooltip = tooltip return t } // MarshalJSON ... func (t Toggle) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "toggle", "text": t.Text, "default": t.Default, } if t.Tooltip != "" { m["tooltip"] = t.Tooltip } return json.Marshal(m) } // Value returns the value filled out by the user. func (t Toggle) Value() bool { return t.value } // Slider represents a slider element. Submitters may move the slider to values within the range of the slider // to select a value. type Slider struct { // Text is the text displayed over the slider element. The text may contain Minecraft formatting codes. Text string // Min and Max are used to specify the minimum and maximum range of the slider. A value lower or higher // than these values cannot be selected. Min, Max float64 // StepSize is the size that one step of the slider takes up. When set to 1.0 for example, a submitter // will be able to select only whole values. StepSize float64 // Default is the default value filled out for the slider. Default float64 // Tooltip is an optional text displayed when hovering over the element's info icon. The icon only // appears when a tooltip is set. Tooltip string value float64 } // NewSlider creates and returns a new Slider using the values passed. func NewSlider(text string, min, max, stepSize, defaultValue float64) Slider { return Slider{Text: text, Min: min, Max: max, StepSize: stepSize, Default: defaultValue} } // WithTooltip returns a copy of the Slider with the tooltip set. func (s Slider) WithTooltip(tooltip string) Slider { s.Tooltip = tooltip return s } // MarshalJSON ... func (s Slider) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "slider", "text": s.Text, "min": s.Min, "max": s.Max, "step": s.StepSize, "default": s.Default, } if s.Tooltip != "" { m["tooltip"] = s.Tooltip } return json.Marshal(m) } // Value returns the value filled out by the user. func (s Slider) Value() float64 { return s.value } // Dropdown represents a dropdown which, when clicked, opens a window with the options set in the Options // field. Submitters may select one of the options. type Dropdown struct { // Text is the text displayed over the dropdown element. The text may contain Minecraft formatting codes. Text string // Options holds a list of options that a Submitter may select. The order of these options is retained // when shown to the submitter of the form. Options []string // DefaultIndex is the index in the Options slice that is used as default. When sent to a Submitter, the // value at this index in the Options slice will be selected. DefaultIndex int // Tooltip is an optional text displayed when hovering over the element's info icon. The icon only // appears when a tooltip is set. Tooltip string value int } // NewDropdown creates and returns new Dropdown using the values passed. func NewDropdown(text string, options []string, defaultIndex int) Dropdown { return Dropdown{Text: text, Options: options, DefaultIndex: defaultIndex} } // WithTooltip returns a copy of the Dropdown with the tooltip set. func (d Dropdown) WithTooltip(tooltip string) Dropdown { d.Tooltip = tooltip return d } // MarshalJSON ... func (d Dropdown) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "dropdown", "text": d.Text, "default": d.DefaultIndex, "options": d.Options, } if d.Tooltip != "" { m["tooltip"] = d.Tooltip } return json.Marshal(m) } // Value returns the value that the Submitter submitted. The value is an index pointing to the selected option // in the Options slice. func (d Dropdown) Value() int { return d.value } // StepSlider represents a slider that has a number of options that may be selected. It is essentially a // combination of a Dropdown and a Slider, looking like a slider but having properties like a dropdown. type StepSlider Dropdown // NewStepSlider creates and returns new StepSlider using the values passed. func NewStepSlider(text string, options []string, defaultIndex int) StepSlider { return StepSlider{Text: text, Options: options, DefaultIndex: defaultIndex} } // WithTooltip returns a copy of the StepSlider with the tooltip set. func (s StepSlider) WithTooltip(tooltip string) StepSlider { s.Tooltip = tooltip return s } // MarshalJSON ... func (s StepSlider) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "step_slider", "text": s.Text, "default": s.DefaultIndex, "steps": s.Options, } if s.Tooltip != "" { m["tooltip"] = s.Tooltip } return json.Marshal(m) } // Value returns the value that the Submitter submitted. The value is an index pointing to the selected option // in the Options slice. func (s StepSlider) Value() int { return s.value } // Button represents a button added to a Menu or Modal form. The button has text on it and an optional image, // which may be either retrieved from a website or the local assets of the game. type Button struct { // Text holds the text displayed on the button. It may use Minecraft formatting codes and may have // newlines. Text string // Image holds a path to an image for the button. The Image may either be a URL pointing to an image, // such as 'https://someimagewebsite.com/someimage.png', or a path pointing to a local asset, such as // 'textures/blocks/grass_carried'. Image string } // NewButton creates and returns a new Button using the text and image passed. func NewButton(text, image string) Button { return Button{Text: text, Image: image} } // MarshalJSON ... func (b Button) MarshalJSON() ([]byte, error) { m := map[string]any{ "type": "button", "text": b.Text, } if b.Image != "" { buttonType := "path" if strings.HasPrefix(b.Image, "http:") || strings.HasPrefix(b.Image, "https:") { buttonType = "url" } m["image"] = map[string]any{"type": buttonType, "data": b.Image} } return json.Marshal(m) } func (Divider) elem() {} func (Header) elem() {} func (Label) elem() {} func (Input) elem() {} func (Toggle) elem() {} func (Slider) elem() {} func (Dropdown) elem() {} func (StepSlider) elem() {} func (Divider) menuElem() {} func (Header) menuElem() {} func (Label) menuElem() {} func (Button) menuElem() {}