form generator
This commit is contained in:
parent
80ae1c4f91
commit
58bd5490e2
7 changed files with 593 additions and 2 deletions
4
.env-dev
4
.env-dev
|
|
@ -5,7 +5,7 @@ APP_NAME=Tabler
|
||||||
APP_ENV=local # local | testing | production
|
APP_ENV=local # local | testing | production
|
||||||
APP_DEBUG_MODE=true
|
APP_DEBUG_MODE=true
|
||||||
App_HTTP_HOST=localhost
|
App_HTTP_HOST=localhost
|
||||||
App_HTTP_PORT=8080
|
App_HTTP_PORT=8081
|
||||||
App_USE_HTTPS=false
|
App_USE_HTTPS=false
|
||||||
App_USE_LETSENCRYPT=false
|
App_USE_LETSENCRYPT=false
|
||||||
App_USE_CORESERVICES=true
|
App_USE_CORESERVICES=true
|
||||||
|
|
@ -60,7 +60,7 @@ CACHE_DRIVER=redis
|
||||||
REDIS_HOST=localhost
|
REDIS_HOST=localhost
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
REDIS_PASSWORD=
|
REDIS_PASSWORD=
|
||||||
REDIS_DB=1
|
REDIS_DB=2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
###### Emails ######
|
###### Emails ######
|
||||||
|
|
|
||||||
|
|
@ -310,3 +310,258 @@ func TablerHome(c *core.Context) *core.Response {
|
||||||
}
|
}
|
||||||
return c.Response.Template("tabler_homepage.html", data)
|
return c.Response.Template("tabler_homepage.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DemoForm1 renders the sample contact form using the form generator.
|
||||||
|
func DemoForm1(c *core.Context) *core.Response {
|
||||||
|
type demoForm1Data struct {
|
||||||
|
TablerPageData
|
||||||
|
FormDefinition FormtablerFormDefinition
|
||||||
|
}
|
||||||
|
data := demoForm1Data{
|
||||||
|
TablerPageData: TablerPageData{
|
||||||
|
PageTitle: "Demo Form 1",
|
||||||
|
PageDescription: "Sample contact form generated from JSON definition",
|
||||||
|
ShowTopbar: true,
|
||||||
|
Sidebar: false,
|
||||||
|
PageHeader: "Contact Form",
|
||||||
|
PagePretitle: "Demo Form Generator",
|
||||||
|
UserName: "Jane Doe",
|
||||||
|
UserRole: "Administrator",
|
||||||
|
NavbarMenu: SampleNavbarMenu(),
|
||||||
|
},
|
||||||
|
FormDefinition: FormtablerFormDefinition{
|
||||||
|
ID: "contact-form",
|
||||||
|
Title: "Contact us",
|
||||||
|
SuccessMessage: "Thanks! We'll get back to you soon.",
|
||||||
|
Method: "POST",
|
||||||
|
Fields: []FormtablerFormField{
|
||||||
|
{
|
||||||
|
Name: "name",
|
||||||
|
Label: "Name",
|
||||||
|
Type: "text",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "Jane Doe",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "email",
|
||||||
|
Label: "Email",
|
||||||
|
Type: "email",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "jane@example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "phone",
|
||||||
|
Label: "Phone",
|
||||||
|
Type: "phone",
|
||||||
|
Required: false,
|
||||||
|
Placeholder: "+1 555 000 0000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "message",
|
||||||
|
Label: "Message",
|
||||||
|
Type: "textarea",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "How can we help?",
|
||||||
|
MaxLength: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return c.Response.Template("apptabler_demoform.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DemoForm2 renders an advanced form using all available field types.
|
||||||
|
func DemoForm2(c *core.Context) *core.Response {
|
||||||
|
type demoForm2Data struct {
|
||||||
|
TablerPageData
|
||||||
|
FormDefinition FormtablerFormDefinition
|
||||||
|
}
|
||||||
|
data := demoForm2Data{
|
||||||
|
TablerPageData: TablerPageData{
|
||||||
|
PageTitle: "Demo Form 2",
|
||||||
|
PageDescription: "Advanced form with all field types",
|
||||||
|
ShowTopbar: true,
|
||||||
|
Sidebar: false,
|
||||||
|
PageHeader: "Advanced Registration Form",
|
||||||
|
PagePretitle: "Demo Form Generator",
|
||||||
|
UserName: "Jane Doe",
|
||||||
|
UserRole: "Administrator",
|
||||||
|
NavbarMenu: SampleNavbarMenu(),
|
||||||
|
},
|
||||||
|
FormDefinition: FormtablerFormDefinition{
|
||||||
|
ID: "advanced-registration",
|
||||||
|
Title: "User Registration",
|
||||||
|
SuccessMessage: "Registration submitted successfully! We'll review your application.",
|
||||||
|
Method: "POST",
|
||||||
|
Columns: 3,
|
||||||
|
FieldsetTitle: "Personal Information",
|
||||||
|
FieldsetDescription: "Please fill in all required fields marked with an asterisk (*).",
|
||||||
|
Fields: []FormtablerFormField{
|
||||||
|
{
|
||||||
|
Name: "first_name",
|
||||||
|
Label: "First Name",
|
||||||
|
Type: "text",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "John",
|
||||||
|
MinLength: 2,
|
||||||
|
MaxLength: 50,
|
||||||
|
Autofocus: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "last_name",
|
||||||
|
Label: "Last Name",
|
||||||
|
Type: "text",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "Doe",
|
||||||
|
MinLength: 2,
|
||||||
|
MaxLength: 50,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "email",
|
||||||
|
Label: "Email Address",
|
||||||
|
Type: "email",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "john.doe@example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "phone",
|
||||||
|
Label: "Phone Number",
|
||||||
|
Type: "phone",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "+1 (555) 000-0000",
|
||||||
|
HelpText: "Include country code for international numbers.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "account_type",
|
||||||
|
Label: "Account Type",
|
||||||
|
Type: "select",
|
||||||
|
Required: true,
|
||||||
|
Options: []FormtablerFormFieldOption{
|
||||||
|
{Label: "Personal", Value: "personal", Selected: true},
|
||||||
|
{Label: "Business", Value: "business"},
|
||||||
|
{Label: "Enterprise", Value: "enterprise"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "password",
|
||||||
|
Label: "Password",
|
||||||
|
Type: "password",
|
||||||
|
Required: true,
|
||||||
|
Placeholder: "••••••••",
|
||||||
|
MinLength: 8,
|
||||||
|
MaxLength: 128,
|
||||||
|
HelpText: "At least 8 characters with uppercase, lowercase and numbers.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "company",
|
||||||
|
Label: "Company Name",
|
||||||
|
Type: "text",
|
||||||
|
Placeholder: "Acme Inc.",
|
||||||
|
HelpText: "Only required for Business and Enterprise accounts.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "website",
|
||||||
|
Label: "Website",
|
||||||
|
Type: "url",
|
||||||
|
Placeholder: "https://example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "bio",
|
||||||
|
Label: "Biography",
|
||||||
|
Type: "textarea",
|
||||||
|
Placeholder: "Tell us about yourself...",
|
||||||
|
MaxLength: 500,
|
||||||
|
HelpText: "Maximum 500 characters.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "birth_date",
|
||||||
|
Label: "Date of Birth",
|
||||||
|
Type: "date",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "preferred_language",
|
||||||
|
Label: "Preferred Language",
|
||||||
|
Type: "select",
|
||||||
|
Options: []FormtablerFormFieldOption{
|
||||||
|
{Label: "English", Value: "en", Selected: true},
|
||||||
|
{Label: "Spanish", Value: "es"},
|
||||||
|
{Label: "French", Value: "fr"},
|
||||||
|
{Label: "German", Value: "de"},
|
||||||
|
{Label: "Japanese", Value: "ja"},
|
||||||
|
{Label: "Chinese", Value: "zh"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "experience_level",
|
||||||
|
Label: "Experience Level",
|
||||||
|
Type: "radio",
|
||||||
|
Required: true,
|
||||||
|
Options: []FormtablerFormFieldOption{
|
||||||
|
{Label: "Beginner", Value: "beginner", Checked: true},
|
||||||
|
{Label: "Intermediate", Value: "intermediate"},
|
||||||
|
{Label: "Advanced", Value: "advanced"},
|
||||||
|
{Label: "Expert", Value: "expert"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "skills",
|
||||||
|
Label: "Skills & Technologies",
|
||||||
|
Type: "checkbox",
|
||||||
|
HelpText: "Select all that apply.",
|
||||||
|
Options: []FormtablerFormFieldOption{
|
||||||
|
{Label: "Go", Value: "go", Checked: true},
|
||||||
|
{Label: "JavaScript", Value: "javascript", Checked: true},
|
||||||
|
{Label: "Python", Value: "python"},
|
||||||
|
{Label: "Rust", Value: "rust"},
|
||||||
|
{Label: "Docker", Value: "docker"},
|
||||||
|
{Label: "Kubernetes", Value: "kubernetes"},
|
||||||
|
{Label: "PostgreSQL", Value: "postgresql"},
|
||||||
|
{Label: "Redis", Value: "redis"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "notifications",
|
||||||
|
Label: "Email Notifications",
|
||||||
|
Type: "toggle",
|
||||||
|
HelpText: "Receive updates about new features and security alerts.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "website_color",
|
||||||
|
Label: "Preferred Accent Color",
|
||||||
|
Type: "color",
|
||||||
|
Value: "#206bc4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "priority_level",
|
||||||
|
Label: "Priority Level",
|
||||||
|
Type: "range",
|
||||||
|
Min: 1,
|
||||||
|
Max: 10,
|
||||||
|
Step: 1,
|
||||||
|
Value: "5",
|
||||||
|
HelpText: "1 = Lowest priority, 10 = Highest priority",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "agree_terms",
|
||||||
|
Label: "I agree to the Terms of Service and Privacy Policy",
|
||||||
|
Type: "checkbox",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "marketing_consent",
|
||||||
|
Label: "I would like to receive marketing communications",
|
||||||
|
Type: "toggle",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "csrf_token",
|
||||||
|
Type: "hidden",
|
||||||
|
Value: "abc123xyz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubmitText: "Create Account",
|
||||||
|
ShowReset: true,
|
||||||
|
ResetText: "Clear All",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return c.Response.Template("apptabler_demoform.html", data)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,60 @@ type AdminCustomersPage struct {
|
||||||
type AuthLockPageData struct {
|
type AuthLockPageData struct {
|
||||||
PersonName string
|
PersonName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormtablerFormFieldOption is an option for select, radio, or checkbox fields.
|
||||||
|
type FormtablerFormFieldOption struct {
|
||||||
|
Label string
|
||||||
|
Value string
|
||||||
|
Selected bool
|
||||||
|
Checked bool
|
||||||
|
Disabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerFormField represents a single field in a JSON-defined form.
|
||||||
|
type FormtablerFormField struct {
|
||||||
|
Name string
|
||||||
|
Label string
|
||||||
|
Type string // "text", "email", "phone", "textarea", "password", "select", "checkbox", "radio", "toggle", "file", "number", "url", "date", "datetime-local", "color", "range", "hidden"
|
||||||
|
Required bool
|
||||||
|
Placeholder string
|
||||||
|
MaxLength int
|
||||||
|
MinLength int
|
||||||
|
Min float64
|
||||||
|
Max float64
|
||||||
|
Step float64
|
||||||
|
Pattern string
|
||||||
|
Value string
|
||||||
|
Options []FormtablerFormFieldOption // for select, radio, checkbox
|
||||||
|
Autofocus bool
|
||||||
|
Readonly bool
|
||||||
|
Disabled bool
|
||||||
|
Multiple bool
|
||||||
|
Accept string // file accept attribute
|
||||||
|
Class string
|
||||||
|
HelpText string
|
||||||
|
ErrorText string
|
||||||
|
Success bool
|
||||||
|
Error bool
|
||||||
|
ColSpan int // for grid layout, 1-12
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerFormDefinition is the top-level structure for a JSON-defined form.
|
||||||
|
type FormtablerFormDefinition struct {
|
||||||
|
ID string
|
||||||
|
Title string
|
||||||
|
SuccessMessage string
|
||||||
|
Fields []FormtablerFormField
|
||||||
|
Method string // "GET" or "POST", default "POST"
|
||||||
|
Action string // form action URL
|
||||||
|
SubmitText string // button text, default "Submit"
|
||||||
|
ResetText string // button text for reset
|
||||||
|
ShowReset bool
|
||||||
|
Class string // form class
|
||||||
|
Layout string // "default", "inline", "horizontal", "card"
|
||||||
|
Columns int // number of columns (1, 2, 3), default 1
|
||||||
|
Enctype string // form enctype
|
||||||
|
NoValidate bool
|
||||||
|
FieldsetTitle string // optional fieldset wrapper
|
||||||
|
FieldsetDescription string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,10 @@ func registerRoutes() {
|
||||||
controller.Get("/admin/customers", controllers.AdminCustomers)
|
controller.Get("/admin/customers", controllers.AdminCustomers)
|
||||||
controller.Post("/admin/customers", controllers.AdminCustomers)
|
controller.Post("/admin/customers", controllers.AdminCustomers)
|
||||||
|
|
||||||
|
// Form generator demo routes
|
||||||
|
controller.Get("/demoform1", controllers.DemoForm1)
|
||||||
|
controller.Get("/demoform2", controllers.DemoForm2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
storage/templates/apptabler_demoform.html
Normal file
1
storage/templates/apptabler_demoform.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{{template "default_layout" .}}
|
||||||
|
|
@ -0,0 +1,272 @@
|
||||||
|
<!-- Form Generator: renders a full HTML form from a FormtablerFormDefinition -->
|
||||||
|
{{define "formtabler_generator"}}
|
||||||
|
<div class="card{{if defaultVal "" .Class}} {{.Class}}{{end}}">
|
||||||
|
{{if .Title}}
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">{{.Title}}</h3>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="card-body">
|
||||||
|
<form
|
||||||
|
id="{{defaultVal "form-generator" .ID}}"
|
||||||
|
method="{{defaultVal "POST" .Method}}"
|
||||||
|
{{if .Action}}action="{{.Action}}"{{end}}
|
||||||
|
{{if .Class}}class="{{.Class}}"{{end}}
|
||||||
|
{{if .Enctype}}enctype="{{.Enctype}}"{{end}}
|
||||||
|
{{if .NoValidate}}novalidate{{end}}
|
||||||
|
>
|
||||||
|
{{if .SuccessMessage}}
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
{{.SuccessMessage}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .FieldsetTitle}}
|
||||||
|
<fieldset class="form-fieldset">
|
||||||
|
<legend>{{.FieldsetTitle}}</legend>
|
||||||
|
{{if .FieldsetDescription}}<p class="text-secondary mb-3">{{.FieldsetDescription}}</p>{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if gt .Columns 1}}
|
||||||
|
<div class="row">
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{$cols := .Columns}}
|
||||||
|
{{$layout := .Layout}}
|
||||||
|
{{range $i, $field := .Fields}}
|
||||||
|
{{if and (gt $cols 1) (eq $layout "horizontal")}}
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
{{else if gt $cols 1}}
|
||||||
|
{{if eq $cols 2}}
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
{{else}}
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq $field.Type "hidden"}}
|
||||||
|
<input type="hidden" name="{{$field.Name}}" value="{{$field.Value}}">
|
||||||
|
{{else if or (eq $field.Type "select") (eq $field.Type "multiselect")}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<select
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-select{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
{{if $field.Autofocus}}autofocus{{end}}
|
||||||
|
{{if eq $field.Type "multiselect"}}multiple{{end}}
|
||||||
|
>
|
||||||
|
{{if not $field.Multiple}}<option value="">{{defaultVal "Select..." $field.Placeholder}}</option>{{end}}
|
||||||
|
{{range $field.Options}}
|
||||||
|
<option value="{{.Value}}"{{if .Selected}} selected{{end}}{{if .Disabled}} disabled{{end}}>{{.Label}}</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
{{if $field.ErrorText}}<div class="invalid-feedback">{{$field.ErrorText}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "textarea"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<textarea
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-control{{if $field.Success}} is-valid{{end}}{{if $field.Error}} is-invalid{{end}}{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
placeholder="{{defaultVal "" $field.Placeholder}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Readonly}}readonly{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
{{if $field.Autofocus}}autofocus{{end}}
|
||||||
|
{{if $field.MaxLength}}maxlength="{{$field.MaxLength}}"{{end}}
|
||||||
|
{{if $field.MinLength}}minlength="{{$field.MinLength}}"{{end}}
|
||||||
|
>{{$field.Value}}</textarea>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
{{if $field.ErrorText}}<div class="invalid-feedback">{{$field.ErrorText}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "checkbox"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-label">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</div>
|
||||||
|
{{if $field.Options}}
|
||||||
|
{{range $field.Options}}
|
||||||
|
<label class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
value="{{.Value}}"
|
||||||
|
{{if .Checked}}checked{{end}}
|
||||||
|
{{if .Disabled}}disabled{{end}}
|
||||||
|
>
|
||||||
|
<span class="form-check-label">{{.Label}}</span>
|
||||||
|
</label>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
<label class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
value="1"
|
||||||
|
{{if eq $field.Value "true"}}checked{{end}}
|
||||||
|
>
|
||||||
|
<span class="form-check-label">{{defaultVal "Yes" $field.Placeholder}}</span>
|
||||||
|
</label>
|
||||||
|
{{end}}
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "radio"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-label">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</div>
|
||||||
|
{{range $field.Options}}
|
||||||
|
<label class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
value="{{.Value}}"
|
||||||
|
{{if .Checked}}checked{{end}}
|
||||||
|
{{if .Disabled}}disabled{{end}}
|
||||||
|
>
|
||||||
|
<span class="form-check-label">{{.Label}}</span>
|
||||||
|
</label>
|
||||||
|
{{end}}
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "toggle"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-check form-switch">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
{{if eq $field.Value "true"}}checked{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
>
|
||||||
|
<span class="form-check-label">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</span>
|
||||||
|
</label>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "file"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-control{{if $field.Success}} is-valid{{end}}{{if $field.Error}} is-invalid{{end}}{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
{{if $field.Multiple}}multiple{{end}}
|
||||||
|
{{if $field.Accept}}accept="{{$field.Accept}}"{{end}}
|
||||||
|
>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
{{if $field.ErrorText}}<div class="invalid-feedback">{{$field.ErrorText}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "color"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-control form-control-color{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
value="{{defaultVal "#206bc4" $field.Value}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "range"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-range{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
value="{{defaultVal "50" $field.Value}}"
|
||||||
|
{{if $field.Min}}min="{{$field.Min}}"{{end}}
|
||||||
|
{{if $field.Max}}max="{{$field.Max}}"{{end}}
|
||||||
|
{{if $field.Step}}step="{{$field.Step}}"{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if eq $field.Type "phone"}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 4h4l2 5l-2.5 1.5a11 11 0 0 0 5 5l1.5 -2.5l5 2v4a2 2 0 0 1 -2 2a16 16 0 0 1 -15 -15a2 2 0 0 1 2 -2" /></svg>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-control{{if $field.Success}} is-valid{{end}}{{if $field.Error}} is-invalid{{end}}{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
placeholder="{{defaultVal "" $field.Placeholder}}"
|
||||||
|
value="{{$field.Value}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Readonly}}readonly{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
{{if $field.Autofocus}}autofocus{{end}}
|
||||||
|
{{if $field.Pattern}}pattern="{{$field.Pattern}}"{{end}}
|
||||||
|
{{if $field.MaxLength}}maxlength="{{$field.MaxLength}}"{{end}}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
{{if $field.ErrorText}}<div class="invalid-feedback">{{$field.ErrorText}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{/* Default: text, email, number, url, date, datetime-local, password, and any unknown type */}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="field-{{$field.Name}}">{{$field.Label}}{{if $field.Required}} <span class="text-danger">*</span>{{end}}</label>
|
||||||
|
<input
|
||||||
|
type="{{$field.Type}}"
|
||||||
|
id="field-{{$field.Name}}"
|
||||||
|
name="{{$field.Name}}"
|
||||||
|
class="form-control{{if $field.Success}} is-valid{{end}}{{if $field.Error}} is-invalid{{end}}{{if defaultVal "" $field.Class}} {{$field.Class}}{{end}}"
|
||||||
|
placeholder="{{defaultVal "" $field.Placeholder}}"
|
||||||
|
value="{{$field.Value}}"
|
||||||
|
{{if $field.Required}}required{{end}}
|
||||||
|
{{if $field.Readonly}}readonly{{end}}
|
||||||
|
{{if $field.Disabled}}disabled{{end}}
|
||||||
|
{{if $field.Autofocus}}autofocus{{end}}
|
||||||
|
{{if $field.Pattern}}pattern="{{$field.Pattern}}"{{end}}
|
||||||
|
{{if $field.MaxLength}}maxlength="{{$field.MaxLength}}"{{end}}
|
||||||
|
{{if $field.MinLength}}minlength="{{$field.MinLength}}"{{end}}
|
||||||
|
{{if $field.Min}}min="{{$field.Min}}"{{end}}
|
||||||
|
{{if $field.Max}}max="{{$field.Max}}"{{end}}
|
||||||
|
{{if $field.Step}}step="{{$field.Step}}"{{end}}
|
||||||
|
>
|
||||||
|
{{if $field.HelpText}}<small class="form-hint">{{$field.HelpText}}</small>{{end}}
|
||||||
|
{{if $field.ErrorText}}<div class="invalid-feedback">{{$field.ErrorText}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if and (gt $cols 1) (eq $layout "horizontal")}}
|
||||||
|
</div>
|
||||||
|
{{else if gt $cols 1}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if gt .Columns 1}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .FieldsetTitle}}
|
||||||
|
</fieldset>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="form-footer{{if .FieldsetTitle}} mt-2{{end}}">
|
||||||
|
<button type="submit" class="btn btn-primary">{{defaultVal "Submit" .SubmitText}}</button>
|
||||||
|
{{if .ShowReset}}
|
||||||
|
<button type="reset" class="btn btn-link link-secondary ms-auto">{{defaultVal "Reset" .ResetText}}</button>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
@ -42,6 +42,8 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if hasField . "FormElements"}}
|
{{else if hasField . "FormElements"}}
|
||||||
{{template "tabler_formelements_content" .FormElements}}
|
{{template "tabler_formelements_content" .FormElements}}
|
||||||
|
{{else if hasField . "FormDefinition"}}
|
||||||
|
{{template "formtabler_generator" .FormDefinition}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.Content}}
|
{{.Content}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue