77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package qslcard
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"hamlog/internal/applog"
|
|
)
|
|
|
|
// CountryInfo resolves the "auto" country element: a display label and the
|
|
// ISO code of the embedded flag ("" = no flag available).
|
|
type CountryInfo struct {
|
|
Label string `json:"label"`
|
|
FlagISO string `json:"flag_iso"`
|
|
}
|
|
|
|
// RenderModel is a template with every placeholder filled, ready for the
|
|
// frontend to instantiate as SVG (editor preview and final rasterization use
|
|
// the same model so output cannot drift from preview).
|
|
type RenderModel struct {
|
|
Template Template `json:"template"`
|
|
QSOFields map[string]string `json:"qso_fields"` // values for qso_box.fields
|
|
}
|
|
|
|
// warnedPlaceholders dedupes the "unknown placeholder" log line so a bulk
|
|
// render doesn't flood the log.
|
|
var warnedPlaceholders sync.Map
|
|
|
|
// Resolve substitutes {profile.*} and {qso.*} placeholders from vars (keys
|
|
// are the full "namespace.key" form) and resolves the country element. An
|
|
// unknown placeholder resolves to "" and is logged once.
|
|
func Resolve(t Template, vars map[string]string, country CountryInfo) RenderModel {
|
|
resolve := func(text string) string {
|
|
return placeholderRe.ReplaceAllStringFunc(text, func(m string) string {
|
|
key := m[1 : len(m)-1] // strip braces → "namespace.key"
|
|
if v, ok := vars[key]; ok {
|
|
return v
|
|
}
|
|
if _, seen := warnedPlaceholders.LoadOrStore(key, true); !seen {
|
|
applog.Printf("qslcard: unknown placeholder %q resolves to empty", m)
|
|
}
|
|
return ""
|
|
})
|
|
}
|
|
|
|
out := t
|
|
out.Elements = make([]Element, len(t.Elements))
|
|
copy(out.Elements, t.Elements)
|
|
for i := range out.Elements {
|
|
e := &out.Elements[i]
|
|
switch e.Type {
|
|
case ElemCallsign, ElemOperator, ElemInfoLine:
|
|
e.Text = resolve(e.Text)
|
|
case ElemCountry:
|
|
if e.Flag == "auto" {
|
|
e.Flag = country.FlagISO
|
|
}
|
|
if e.Label == "auto" {
|
|
e.Label = country.Label
|
|
}
|
|
}
|
|
}
|
|
if t.QSOBox != nil {
|
|
box := *t.QSOBox
|
|
box.Title = resolve(box.Title)
|
|
box.Footer = resolve(box.Footer)
|
|
out.QSOBox = &box
|
|
}
|
|
|
|
model := RenderModel{Template: out, QSOFields: map[string]string{}}
|
|
if out.QSOBox != nil {
|
|
for _, f := range out.QSOBox.Fields {
|
|
model.QSOFields[f] = vars["qso."+f]
|
|
}
|
|
}
|
|
return model
|
|
}
|