dialog manager extended to be able to produce the New Account dialog
This commit is contained in:
+107
@@ -12,12 +12,21 @@ package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/config"
|
||||
"github.com/CloudyKit/jet/v6"
|
||||
"github.com/CloudyKit/jet/v6/loaders/embedfs"
|
||||
"github.com/CloudyKit/jet/v6/loaders/multi"
|
||||
"github.com/biter777/countries"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
@@ -27,6 +36,96 @@ var static_views embed.FS
|
||||
// views is the main Jet template repository.
|
||||
var views *jet.Set
|
||||
|
||||
var cachedCountryList []countries.CountryCode = nil
|
||||
|
||||
var countryListMutex sync.Mutex
|
||||
|
||||
func internalGetCountryList() []countries.CountryCode {
|
||||
countryListMutex.Lock()
|
||||
defer countryListMutex.Unlock()
|
||||
if cachedCountryList == nil {
|
||||
c := countries.All()
|
||||
slices.SortFunc(c, func(a countries.CountryCode, b countries.CountryCode) int {
|
||||
return strings.Compare(a.Info().Name, b.Info().Name)
|
||||
})
|
||||
cachedCountryList = c
|
||||
}
|
||||
return cachedCountryList
|
||||
}
|
||||
|
||||
// getCountryList is a wrapper around countries.All() to be added to the template context.
|
||||
func getCountryList(a jet.Arguments) reflect.Value {
|
||||
return reflect.ValueOf(internalGetCountryList())
|
||||
}
|
||||
|
||||
// getMonthList is a simple wrapper that returns the names of the months to the template context.
|
||||
func getMonthList(a jet.Arguments) reflect.Value {
|
||||
rc := make([]string, 12)
|
||||
for m := time.January; m <= time.December; m++ {
|
||||
rc[m-time.January] = m.String()
|
||||
}
|
||||
return reflect.ValueOf(rc)
|
||||
}
|
||||
|
||||
// countRanger is a Ranger that can count from one value to another with a certain step.
|
||||
type countRanger struct {
|
||||
i int
|
||||
val int64
|
||||
step int64
|
||||
to int64
|
||||
}
|
||||
|
||||
/* Range (from Ranger) returns the "next" value of this iterator.
|
||||
* Returns:
|
||||
* Next index of the returned value
|
||||
* Next returned value
|
||||
* true if this is the last iteration, false if not
|
||||
*/
|
||||
func (r *countRanger) Range() (reflect.Value, reflect.Value, bool) {
|
||||
r.i++
|
||||
r.val += r.step
|
||||
var end bool
|
||||
if r.step < 0 {
|
||||
end = r.val <= r.to
|
||||
} else {
|
||||
end = r.val >= r.to
|
||||
}
|
||||
return reflect.ValueOf(r.i), reflect.ValueOf(r.val), end
|
||||
}
|
||||
|
||||
// ProvidesIndex (from Ranger) returns true to indicate that this Ranger has indexes.
|
||||
func (r *countRanger) ProvidesIndex() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// makeIntRange creates and returns a countRanger.
|
||||
func makeIntRange(a jet.Arguments) reflect.Value {
|
||||
from := a.Get(0).Convert(reflect.TypeFor[int64]()).Int()
|
||||
to := a.Get(1).Convert(reflect.TypeFor[int64]()).Int()
|
||||
step := a.Get(2).Convert(reflect.TypeFor[int64]()).Int()
|
||||
rc := &countRanger{i: -1, val: from - step, step: step, to: to}
|
||||
return reflect.ValueOf(rc).Convert(reflect.TypeFor[jet.Ranger]())
|
||||
}
|
||||
|
||||
// makeYearRange parses a year parameter and creates a countRanger that reflects it.
|
||||
func makeYearRange(a jet.Arguments) reflect.Value {
|
||||
param := a.Get(0).Convert(reflect.TypeFor[string]()).String()
|
||||
yearRegex, _ := regexp.Compile(`year:(\S+)(\s+.+)?$`)
|
||||
m := yearRegex.FindStringSubmatch(param)
|
||||
if m != nil {
|
||||
count, err := strconv.Atoi(m[1])
|
||||
if err == nil {
|
||||
start_year := time.Now().Year()
|
||||
rc := &countRanger{i: -1, val: int64(start_year) + 1, step: -1, to: int64(start_year + count - 1)}
|
||||
return reflect.ValueOf(rc).Convert(reflect.TypeFor[jet.Ranger]())
|
||||
} else {
|
||||
return reflect.ValueOf(err)
|
||||
}
|
||||
} else {
|
||||
return reflect.ValueOf(fmt.Errorf("cannot locate year: marker in param"))
|
||||
}
|
||||
}
|
||||
|
||||
// SetupTemplates is called to set up the template renderer after the configuration is loaded.
|
||||
func SetupTemplates() {
|
||||
views = jet.NewSet(
|
||||
@@ -39,6 +138,13 @@ func SetupTemplates() {
|
||||
views.AddGlobal("AmsterdamVersion", config.AMSTERDAM_VERSION)
|
||||
views.AddGlobal("AmsterdamCopyright", config.AMSTERDAM_COPYRIGHT)
|
||||
views.AddGlobal("GlobalConfig", config.GlobalConfig)
|
||||
views.AddGlobalFunc("GetCountryList", getCountryList)
|
||||
views.AddGlobalFunc("GetMonthList", getMonthList)
|
||||
views.AddGlobalFunc("MakeIntRange", makeIntRange)
|
||||
views.AddGlobalFunc("MakeYearRange", makeYearRange)
|
||||
|
||||
// preload the country list in the background
|
||||
go internalGetCountryList()
|
||||
}
|
||||
|
||||
// TemplateRenderer is the Renderer instance set into the Echo context at creation time, to render Jet templates.
|
||||
@@ -55,6 +161,7 @@ type TemplateRenderer struct{}
|
||||
*/
|
||||
func (r *TemplateRenderer) Render(w io.Writer, name string, data any, c echo.Context) error {
|
||||
view, err := views.GetTemplate(name)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user