added dialog for editing community profile
This commit is contained in:
+98
-24
@@ -23,17 +23,26 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// DialogItemChoice holds a dialog item choice (only needed in case of defined dropdowns)
|
||||
type DialogItemChoice struct {
|
||||
Id string `yaml:"id"`
|
||||
Text string `yaml:"text"`
|
||||
Default bool `yaml:"default,omitempty"`
|
||||
}
|
||||
|
||||
// DialogItem holds the dialog item definition.
|
||||
type DialogItem struct {
|
||||
Type string `yaml:"type"`
|
||||
Name string `yaml:"name"`
|
||||
Caption string `yaml:"caption,omitempty"`
|
||||
Subcaption string `yaml:"subcaption,omitempty"`
|
||||
Required bool `yaml:"required,omitempty"`
|
||||
Size int `yaml:"size,omitempty"`
|
||||
MaxLength int `yaml:"maxlength,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
Param string `yaml:"param,omitempty"`
|
||||
Type string `yaml:"type"`
|
||||
Name string `yaml:"name"`
|
||||
Caption string `yaml:"caption,omitempty"`
|
||||
Subcaption string `yaml:"subcaption,omitempty"`
|
||||
Required bool `yaml:"required,omitempty"`
|
||||
Disabled bool `yaml:"disabled,omitempty"`
|
||||
Size int `yaml:"size,omitempty"`
|
||||
MaxLength int `yaml:"maxlength,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
Param string `yaml:"param,omitempty"`
|
||||
Choices []DialogItemChoice `yaml:"choices,omitempty"`
|
||||
AuxData any
|
||||
}
|
||||
|
||||
@@ -44,6 +53,7 @@ type Dialog struct {
|
||||
Options string `yaml:"options,omitempty"`
|
||||
MenuSelector string `yaml:"menuSelector,omitempty"`
|
||||
Title string `yaml:"title"`
|
||||
Subtitle string `yaml:"subtitle,omitempty"`
|
||||
Action string `yaml:"action"`
|
||||
Instructions string `yaml:"instructions,omitempty"`
|
||||
Fields []DialogItem `yaml:"fields"`
|
||||
@@ -82,6 +92,9 @@ func AmLoadDialog(name string) (*Dialog, error) {
|
||||
if fld.Type == "date" && fld.Param == "" {
|
||||
d.Fields[i].Param = "year:-100"
|
||||
}
|
||||
if fld.Type == "dropdown" && len(fld.Choices) == 0 {
|
||||
return nil, fmt.Errorf("dropdown field %s in dialog %s has no choices", fld.Name, name)
|
||||
}
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
@@ -184,11 +197,29 @@ func (fld *DialogItem) SetVal(p *string) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetInt sets the value of a field to an integer.
|
||||
func (fld *DialogItem) SetInt(v int) {
|
||||
fld.Value = fmt.Sprintf("%d", v)
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the field is empty.
|
||||
func (fld *DialogItem) IsEmpty() bool {
|
||||
return len(fld.Value) == 0
|
||||
}
|
||||
|
||||
// SetCommunity alters a dialog's content to reflect the community.
|
||||
func (d *Dialog) SetCommunity(comm *database.Community) {
|
||||
d.Title = strings.ReplaceAll(d.Title, "[CNAME]", comm.Name)
|
||||
d.Subtitle = strings.ReplaceAll(d.Subtitle, "[CNAME]", comm.Name)
|
||||
d.Action = strings.ReplaceAll(d.Action, "[CID]", comm.Alias)
|
||||
for i, fld := range d.Fields {
|
||||
switch fld.Type {
|
||||
case "userphoto", "communitylogo":
|
||||
d.Fields[i].Param = strings.ReplaceAll(fld.Param, "[CID]", comm.Alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Field returns a pointer to a dialog's field, given its name.
|
||||
* Parameters:
|
||||
* name - The name of the field to find.
|
||||
@@ -224,6 +255,46 @@ func (d *Dialog) Render(ctxt AmContext) (string, any, error) {
|
||||
if d.Fields[i].Value == "" {
|
||||
d.Fields[i].Value = config.GlobalConfig.Defaults.TimeZone
|
||||
}
|
||||
case "dropdown":
|
||||
defv := ""
|
||||
for _, ch := range fld.Choices {
|
||||
if ch.Default {
|
||||
defv = ch.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
if d.Fields[i].Value == "" {
|
||||
d.Fields[i].Value = defv
|
||||
} else {
|
||||
ok := false
|
||||
for _, ch := range fld.Choices {
|
||||
if d.Fields[i].Value == ch.Id {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
d.Fields[i].Value = defv
|
||||
}
|
||||
}
|
||||
case "rolelist":
|
||||
rl := database.AmRoleList(fld.Param)
|
||||
defv := rl.Default().LevelStr()
|
||||
if d.Fields[i].Value == "" {
|
||||
d.Fields[i].Value = defv
|
||||
} else {
|
||||
ok := false
|
||||
for _, r := range rl.Roles() {
|
||||
if d.Fields[i].Value == r.LevelStr() {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
if !ok {
|
||||
d.Fields[i].Value = defv
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: want to do something like dropdown but not sure what yet
|
||||
}
|
||||
}
|
||||
if d.MenuSelector != "" && d.MenuSelector != "nochange" {
|
||||
@@ -312,7 +383,7 @@ func (d *Dialog) LoadFromForm(ctxt AmContext) {
|
||||
}
|
||||
}
|
||||
d.Fields[i].AuxData = dvals
|
||||
case "userphoto":
|
||||
case "userphoto", "communitylogo":
|
||||
d.Fields[i].Value = ctxt.FormField(fmt.Sprintf("%s_data", fld.Name))
|
||||
default:
|
||||
d.Fields[i].Value = ctxt.FormField(fld.Name)
|
||||
@@ -468,20 +539,23 @@ func validateDateField(fld *DialogItem) error {
|
||||
|
||||
// validators maps the field types to validator functions.
|
||||
var validators = map[string]validatorFunc{
|
||||
"ams_id": validateAmsIdField,
|
||||
"button": nilValidator,
|
||||
"checkbox": nilValidator,
|
||||
"countrylist": validateCountryField,
|
||||
"date": validateDateField,
|
||||
"email": validateEmailField,
|
||||
"header": nilValidator,
|
||||
"hidden": nilValidator,
|
||||
"integer": validateIntegerField,
|
||||
"localelist": nilValidator, // TODO
|
||||
"password": validateTextField,
|
||||
"text": validateTextField,
|
||||
"tzlist": nilValidator, // TODO
|
||||
"userphoto": nilValidator,
|
||||
"ams_id": validateAmsIdField,
|
||||
"button": nilValidator,
|
||||
"checkbox": nilValidator,
|
||||
"communitylogo": nilValidator,
|
||||
"countrylist": validateCountryField,
|
||||
"date": validateDateField,
|
||||
"dropdown": nilValidator,
|
||||
"email": validateEmailField,
|
||||
"header": nilValidator,
|
||||
"hidden": nilValidator,
|
||||
"integer": validateIntegerField,
|
||||
"localelist": nilValidator,
|
||||
"password": validateTextField,
|
||||
"rolelist": nilValidator,
|
||||
"text": validateTextField,
|
||||
"tzlist": nilValidator,
|
||||
"userphoto": nilValidator,
|
||||
}
|
||||
|
||||
/* Validate validates the values in the dialog.
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#
|
||||
# Amsterdam Web Communities System
|
||||
# Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
name: "community.profile"
|
||||
formName: "comprofform"
|
||||
menuSelector: "community"
|
||||
title: "Edit Community Profile:"
|
||||
subtitle: "[CNAME]"
|
||||
action: "/comm/[CID]/admin/profile"
|
||||
fields:
|
||||
- type: "hidden"
|
||||
name: "cc"
|
||||
value: ""
|
||||
- type: "header"
|
||||
name: "header1"
|
||||
caption: "Basic Information"
|
||||
- type: "text"
|
||||
name: "name"
|
||||
caption: "Community Name"
|
||||
required: true
|
||||
size: 32
|
||||
maxLength: 128
|
||||
- type: "ams_id"
|
||||
name: "alias"
|
||||
caption: "Community Alias"
|
||||
required: true
|
||||
size: 32
|
||||
maxlength: 32
|
||||
- type: "text"
|
||||
name: "synopsis"
|
||||
caption: "Synopsis"
|
||||
size: 32
|
||||
maxLength: 255
|
||||
- type: "text"
|
||||
name: "rules"
|
||||
caption: "Rules"
|
||||
size: 32
|
||||
maxLength: 255
|
||||
- type: "localelist"
|
||||
name: "language"
|
||||
caption: "Primary Language"
|
||||
required: true
|
||||
- type: "text"
|
||||
name: "url"
|
||||
caption: "Home Page"
|
||||
subcaption: "(URL)"
|
||||
size: 32
|
||||
maxlength: 255
|
||||
- type: "communitylogo"
|
||||
name: "logo"
|
||||
caption: "Community logo"
|
||||
param: "/TODO/comm/[CID]/admin/logo"
|
||||
- type: "header"
|
||||
name: "header2"
|
||||
caption: "Location"
|
||||
- type: "text"
|
||||
name: "company"
|
||||
caption: "Company"
|
||||
size: 32
|
||||
maxlength: 255
|
||||
- type: "text"
|
||||
name: "addr1"
|
||||
caption: "Address"
|
||||
size: 32
|
||||
maxlength: 255
|
||||
- type: "text"
|
||||
name: "addr2"
|
||||
caption: "Address"
|
||||
subcaption: "(line 2)"
|
||||
size: 32
|
||||
maxlength: 255
|
||||
- type: "text"
|
||||
name: "loc"
|
||||
caption: "City"
|
||||
required: true
|
||||
size: 32
|
||||
maxlength: 64
|
||||
- type: "text"
|
||||
name: "reg"
|
||||
caption: "State/Province"
|
||||
required: true
|
||||
size: 32
|
||||
maxlength: 64
|
||||
- type: "text"
|
||||
name: "pcode"
|
||||
caption: "Zip/Postal Code"
|
||||
required: true
|
||||
size: 32
|
||||
maxlength: 64
|
||||
- type: "countrylist"
|
||||
name: "country"
|
||||
caption: "Country"
|
||||
required: true
|
||||
- type: "header"
|
||||
name: "header3"
|
||||
caption: "Security"
|
||||
- type: "dropdown"
|
||||
name: "comtype"
|
||||
caption: "Community type"
|
||||
required: true
|
||||
choices:
|
||||
- id: "0"
|
||||
text: "Public"
|
||||
default: true
|
||||
- id: "1"
|
||||
text: "Private"
|
||||
- type: "text"
|
||||
name: "joinkey"
|
||||
caption: "Join Key"
|
||||
subcaption: "(for private communities)"
|
||||
size: 32
|
||||
maxLength: 64
|
||||
- type: "checkbox"
|
||||
name: "membersonly"
|
||||
caption: "Allow only members to access this community"
|
||||
- type: "dropdown"
|
||||
name: "hidemode"
|
||||
caption: "Community visibility"
|
||||
required: true
|
||||
choices:
|
||||
- id: "NONE"
|
||||
text: "Show in both directory and search"
|
||||
default: true
|
||||
- id: "DIRECTORY"
|
||||
text: "Hide in directory, but not in search"
|
||||
- id: "BOTH"
|
||||
text: "Hide in both directory and search"
|
||||
- type: "rolelist"
|
||||
name: "read_lvl"
|
||||
caption: "Security level required to read contents"
|
||||
required: true
|
||||
param: "Community.Read"
|
||||
- type: "rolelist"
|
||||
name: "write_lvl"
|
||||
caption: "Security level required to update profile"
|
||||
required: true
|
||||
param: "Community.Write"
|
||||
- type: "rolelist"
|
||||
name: "create_lvl"
|
||||
caption: "Security level required to create new subobjects"
|
||||
required: true
|
||||
param: "Community.Create"
|
||||
- type: "rolelist"
|
||||
name: "delete_lvl"
|
||||
caption: "Security level required to delete community"
|
||||
required: true
|
||||
param: "Community.Delete"
|
||||
- type: "rolelist"
|
||||
name: "join_lvl"
|
||||
caption: "Security level required to join community"
|
||||
required: true
|
||||
param: "Community.Join"
|
||||
- type: "header"
|
||||
name: "header4"
|
||||
caption: "Conferencing Options"
|
||||
- type: "checkbox"
|
||||
name: "pic_in_post"
|
||||
caption: "Display user pictures next to posts in conferences"
|
||||
subcaption: "(by default; user can override)"
|
||||
- type: "button"
|
||||
name: "update"
|
||||
caption: "Update"
|
||||
param: "blue"
|
||||
- type: "button"
|
||||
name: "cancel"
|
||||
caption: "Cancel"
|
||||
param: "red"
|
||||
+5
-5
@@ -61,15 +61,15 @@ menudefs:
|
||||
community. Use with care and review all changes before applying them to the community.
|
||||
items:
|
||||
- text: "Community Profile"
|
||||
link: "/TODO/comm/[CID]/admin/profile"
|
||||
permission: "Community.ShowAdmin"
|
||||
link: "/comm/[CID]/admin/profile"
|
||||
permission: "Community.Write"
|
||||
- text: "Set Community Category"
|
||||
link: "/TODO/comm/[CID]/admin/category"
|
||||
permission: "Community.ShowAdmin"
|
||||
permission: "Community.Write"
|
||||
ifdef: "USECAT"
|
||||
- text: "Set Community Services"
|
||||
link: "/TODO/comm/[CID]/admin/services"
|
||||
permission: "Community.ShowAdmin"
|
||||
permission: "Community.Write"
|
||||
disabled: true
|
||||
- text: "Membership Control"
|
||||
link: "/TODO/comm/[CID]/admin/members"
|
||||
@@ -82,5 +82,5 @@ menudefs:
|
||||
permission: "Community.ShowAdmin"
|
||||
- text: "Delete Community"
|
||||
link: "/TODO/comm/[CID]/admin/delete"
|
||||
permission: "Community.Destroy"
|
||||
permission: "Community.Delete"
|
||||
hazard: true
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/config"
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
"git.erbosoft.com/amy/amsterdam/util"
|
||||
"github.com/CloudyKit/jet/v6"
|
||||
"github.com/CloudyKit/jet/v6/loaders/embedfs"
|
||||
@@ -235,6 +236,10 @@ func SetupTemplates() {
|
||||
s := a.Get(0).Convert(reflect.TypeFor[string]()).String()
|
||||
return reflect.ValueOf(AmMenu(s))
|
||||
})
|
||||
views.AddGlobalFunc("AmRoleList", func(a jet.Arguments) reflect.Value {
|
||||
s := a.Get(0).Convert(reflect.TypeFor[string]()).String()
|
||||
return reflect.ValueOf(database.AmRoleList(s))
|
||||
})
|
||||
views.AddGlobalFunc("CapitalizeString", func(a jet.Arguments) reflect.Value {
|
||||
s := a.Get(0).Convert(reflect.TypeFor[string]()).String()
|
||||
return reflect.ValueOf(util.CapitalizeString(s))
|
||||
|
||||
+85
-25
@@ -10,6 +10,9 @@
|
||||
<div class="p-4">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-blue-800 text-4xl font-bold mb-2">{{ amsterdam_dialog.Title }}</h1>
|
||||
{{ if amsterdam_dialog.Subtitle != "" }}
|
||||
<span class="text-blue-800 text-2xl font-bold ml-2">{{ amsterdam_dialog.Subtitle }}</span>
|
||||
{{ end }}
|
||||
<hr class="border-2 border-gray-400 w-4/5 mb-4">
|
||||
</div>
|
||||
<form name="{{ amsterdam_dialog.FormName }}" method="POST" action="{{ amsterdam_dialog.Action }}" class="max-w-2xl">
|
||||
@@ -58,26 +61,28 @@
|
||||
{{ range amsterdam_dialog.Fields }}
|
||||
{{ if .Type == "text" || .Type == "ams_id" || .Type == "email" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}:
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
<input type="text" id="{{ .Name }}" name="{{ .Name }}"
|
||||
{{ if .Size > 0 }}size="{{ .Size }}"{{ end }}
|
||||
{{ if .MaxLength > 0 }}maxlength="{{ .MaxLength }}"{{ end }}
|
||||
value="{{ .Value }}"
|
||||
value="{{ .Value }}" {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
|
||||
</div>
|
||||
{{ else if .Type == "integer" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}:
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
<input type="text" id="{{ .Name }}" name="{{ .Name }}"
|
||||
{{ if .Size > 0 }}size="{{ .Size }}"{{ end }}
|
||||
{{ if .MaxLength > 0 }}maxlength="{{ .MaxLength }}"{{ end }}
|
||||
value="{{ .Value }}"
|
||||
value="{{ .Value }}" {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
|
||||
{{ vr := .ValueRange() }}
|
||||
{{ if vr.Low != -1 && vr.High != -1 }}
|
||||
@@ -86,36 +91,69 @@
|
||||
</div>
|
||||
{{ else if .Type == "password" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}:
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
<input type="password" id="{{ .Name }}" name="{{ .Name }}"
|
||||
{{ if .Size > 0 }}size="{{ .Size }}"{{ end }}
|
||||
{{ if .MaxLength > 0 }}maxlength="{{ .MaxLength }}"{{ end }}
|
||||
value="{{ .Value }}"
|
||||
value="{{ .Value }}" {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
|
||||
</div>
|
||||
{{ else if .Type == "checkbox" }}
|
||||
<div class="flex items-center">
|
||||
<div class="w-24 text-right pr-4">
|
||||
<input type="checkbox" id="{{ .Name }}" name="{{ .Name }}"
|
||||
value="Y" {{ if .Value != "" }}checked{{ end }}
|
||||
value="Y" {{ if .Value != "" }}checked{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />
|
||||
</div>
|
||||
<label for="{{ .Name }}" class="flex-1 text-black text-sm">
|
||||
<label for="{{ .Name }}" class="flex-1 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
</div>
|
||||
{{ else if .Type == "countrylist" }}
|
||||
{{ else if .Type == "dropdown" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
{{ v := .Value }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
{{ range .Choices }}
|
||||
<option value="{{ .Id }}" {{ if .Id == v }}selected{{ end }}>{{ .Text }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
{{ else if .Type == "rolelist" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
{{ v := .Value }}
|
||||
{{ rl := AmRoleList(.Param) }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
{{ range rl.Roles() }}
|
||||
<option value="{{ .LevelStr() }}" {{ if .LevelStr() == v }}selected{{ end }}>{{ .Name() }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
{{ else if .Type == "countrylist" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
{{ v := .Value }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="XX" {{ if v == "XX" }}selected{{ end }}>🏳️ (unknown)</option>
|
||||
{{ range GetCountryList() }}
|
||||
@@ -126,12 +164,13 @@
|
||||
</div>
|
||||
{{ else if .Type == "localelist" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
{{ v := .Value }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 max-w-md px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
{{ range GetLanguageList() }}
|
||||
<option value="{{ .Tag }}" {{ if .Tag == v }}selected{{ end }}>{{ .Name }}</option>
|
||||
@@ -140,12 +179,13 @@
|
||||
</div>
|
||||
{{ else if .Type == "tzlist" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label for="{{ .Name }}"
|
||||
class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
{{ v := .Value }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }}
|
||||
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }} {{ if .Disabled }}disabled{{ end }}
|
||||
class="flex-1 max-w-md px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
{{ range GetTimeZoneList() }}
|
||||
<option value="{{ . }}" {{ if v == . }}selected{{ end }}>{{ . }}</option>
|
||||
@@ -155,25 +195,27 @@
|
||||
{{ else if .Type == "date" }}
|
||||
{{ dv := .DateValues() }}
|
||||
<div class="flex items-center">
|
||||
<label class="w-64 text-right pr-4 text-black text-sm">
|
||||
<label class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm">
|
||||
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
|
||||
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<select name="{{ .Name }}_month"
|
||||
<select name="{{ .Name }}_month" {{ if .Disabled }}disabled{{ end }}
|
||||
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="-1" {{ if dv[0] == -1 }}selected{{ end }}>---</option>
|
||||
{{ range i := GetMonthList() }}
|
||||
<option value="{{ i + 1 }}" {{ if dv[0] == i + 1 }}selected{{ end }}>{{ . }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
<select name="{{ .Name }}_day" class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<select name="{{ .Name }}_day" {{ if .Disabled }}disabled{{ end }}
|
||||
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="-1" {{ if dv[1] == -1 }}selected{{ end }}>---</option>
|
||||
{{ range MakeIntRange(1, 32, 1) }}
|
||||
<option value="{{ . }}" {{ if dv[1] == . }}selected{{ end }}>{{ . }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
<select name="{{ .Name }}_year" class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<select name="{{ .Name }}_year" {{ if .Disabled }}disabled{{ end }}
|
||||
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="-1" {{ if dv[2] == -1 }}selected{{ end }}>---</option>
|
||||
{{ range MakeYearRange(.Param) }}
|
||||
<option value="{{ . }}" {{ if dv[2] == . }}selected{{ end }}>{{ . }}</option>
|
||||
@@ -183,13 +225,31 @@
|
||||
</div>
|
||||
{{ else if .Type == "userphoto" }}
|
||||
<div class="flex items-start">
|
||||
<label class="w-64 text-right pr-4 text-black text-sm pt-2">{{ .Caption }}
|
||||
<label class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm pt-2">{{ .Caption }}
|
||||
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
|
||||
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
|
||||
<a href="/profile_photo?tgt={{ target | url }}"
|
||||
class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
||||
<img src="{{ .Value }}" alt="Click to upload photo" class="w-25 h-25">
|
||||
</a>
|
||||
{{ if .Disabled }}
|
||||
<img src="{{ .Value }}" class="w-25 h-25">
|
||||
{{ else }}
|
||||
<a href="/profile_photo?tgt={{ target | url }}"
|
||||
class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
||||
<img src="{{ .Value }}" alt="Click to upload photo" class="w-25 h-25">
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ else if .Type == "communitylogo" }}
|
||||
<div class="flex items-start">
|
||||
<label class="w-64 text-right pr-4 {{ if .Disabled }}text-gray-400{{ else }}text-black{{ end }} text-sm pt-2">{{ .Caption }}
|
||||
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
|
||||
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
|
||||
{{ if .Disabled }}
|
||||
<img src="/img/builtin/default-community.jpg" class="w-28 h-16 rounded">
|
||||
{{ else }}
|
||||
<a href="{{ .Param }}"
|
||||
class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
||||
<img src="/img/builtin/default-community.jpg" alt="Click to upload logo" class="w-28 h-16 rounded">
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ else if .Type == "header" }}
|
||||
<h2 class="text-lg font-bold text-black mb-4">{{ .Caption }}</h2>
|
||||
@@ -202,7 +262,7 @@
|
||||
{{ range amsterdam_dialog.Fields }}
|
||||
{{ if .Type == "button" }}
|
||||
{{ clstmp := "bg-" + .Param + "-600 hover:bg-" + .Param + "-700" }}
|
||||
<button type="submit" name="{{ .Name }}"
|
||||
<button type="submit" name="{{ .Name }}" {{ if .Disabled }}disabled{{ end }}
|
||||
class="{{ clstmp }} text-white px-6 py-2 rounded font-medium transition-colors">{{ .Caption }}</button>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user