diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dbx/db.go | 11 | ||||
-rw-r--r-- | src/dbx/mintages.go | 182 | ||||
-rw-r--r-- | src/dbx/sql/last.sql | 28 | ||||
-rw-r--r-- | src/dbx/users.go | 7 | ||||
-rw-r--r-- | src/http.go | 51 | ||||
-rw-r--r-- | src/tables.go | 108 | ||||
-rw-r--r-- | src/templates.go | 10 | ||||
-rw-r--r-- | src/templates/-base.html.tmpl | 38 | ||||
-rw-r--r-- | src/templates/coins-mintages.html.tmpl | 91 |
9 files changed, 294 insertions, 232 deletions
diff --git a/src/dbx/db.go b/src/dbx/db.go index b839531..5ee3782 100644 --- a/src/dbx/db.go +++ b/src/dbx/db.go @@ -1,6 +1,7 @@ package dbx import ( + "context" "fmt" "io/fs" "log" @@ -20,6 +21,16 @@ var ( func Init(sqlDir fs.FS) { db = sqlx.MustConnect("sqlite3", DBName) atexit.Register(Close) + + conn := Try2(db.Conn(context.Background())) + Try(conn.Raw(func(driverConn any) error { + return driverConn.(*sqlite3.SQLiteConn).RegisterFunc("C_", + func(s, _ string) string { + return s + }, true) + })) + conn.Close() + Try(applyMigrations(sqlDir)) /* TODO: Remove debug code */ diff --git a/src/dbx/mintages.go b/src/dbx/mintages.go index 9b98bd6..2223eff 100644 --- a/src/dbx/mintages.go +++ b/src/dbx/mintages.go @@ -1,21 +1,22 @@ package dbx import ( + "context" "database/sql" "slices" ) type CountryMintageData struct { Standard []MSCountryRow - Commemorative []MCCountryRow + Commemorative []MCommemorative } type YearMintageData struct { Standard []MSYearRow - Commemorative []MCYearRow + Commemorative []MCommemorative } -type msRowInternal struct { +type msRow struct { Country string Type MintageType Year int @@ -25,47 +26,29 @@ type msRowInternal struct { Reference sql.Null[string] } -type mcRowInternal struct { - Country string - Type MintageType - Year int - Name string - Number int - Mintmark sql.Null[string] - Mintage sql.Null[int] - Reference sql.Null[string] -} - type MSCountryRow struct { Year int - Mintmark string - Mintages [ndenoms]int - References []string -} - -type MCCountryRow struct { - Year int - Name string - Number int - Mintmark string - Mintage int - Reference string + Mintmark sql.Null[string] + Mintages [ndenoms]sql.Null[int] + References [ndenoms]sql.Null[string] } type MSYearRow struct { Country string - Mintmark string - Mintages [ndenoms]int - References []string + Mintmark sql.Null[string] + Mintages [ndenoms]sql.Null[int] + References [ndenoms]sql.Null[string] } -type MCYearRow struct { - Country string - Name string +type MCommemorative struct { + Country string + Type MintageType + Year int + Name string Number int - Mintmark string - Mintage int - Reference string + Mintmark sql.Null[string] + Mintage sql.Null[int] + Reference sql.Null[string] } type MintageType int @@ -77,12 +60,6 @@ const ( TypeProof ) -/* DO NOT REORDER! */ -const ( - MintageUnknown = -iota - 1 - MintageInvalid -) - const ndenoms = 8 func NewMintageType(s string) MintageType { @@ -103,10 +80,10 @@ func GetMintagesByYear(year int, typ MintageType) (YearMintageData, error) { var ( zero YearMintageData xs []MSYearRow - ys []MCYearRow + ys []MCommemorative ) - rs, err := db.Queryx(` + rs, err := db.QueryxContext(context.TODO(), ` SELECT * FROM mintages_s WHERE year = ? AND type = ? ORDER BY country, mintmark, denomination @@ -116,28 +93,22 @@ func GetMintagesByYear(year int, typ MintageType) (YearMintageData, error) { } for rs.Next() { - var x msRowInternal + var x msRow if err = rs.StructScan(&x); err != nil { return zero, err } loop: msr := MSYearRow{ - Country: x.Country, - Mintmark: sqlOr(x.Mintmark, ""), - References: make([]string, 0, ndenoms), - } - for i := range msr.Mintages { - msr.Mintages[i] = MintageUnknown - } - msr.Mintages[denomToIdx(x.Denomination)] = - sqlOr(x.Mintage, MintageUnknown) - if x.Reference.Valid { - msr.References = append(msr.References, x.Reference.V) + Country: x.Country, + Mintmark: x.Mintmark, } + i := denomToIdx(x.Denomination) + msr.Mintages[i] = x.Mintage + msr.References[i] = x.Reference for rs.Next() { - var y msRowInternal + var y msRow if err = rs.StructScan(&y); err != nil { return zero, err } @@ -148,11 +119,9 @@ func GetMintagesByYear(year int, typ MintageType) (YearMintageData, error) { goto loop } - msr.Mintages[denomToIdx(y.Denomination)] = - sqlOr(y.Mintage, MintageUnknown) - if y.Reference.Valid { - msr.References = append(msr.References, y.Reference.V) - } + i = denomToIdx(y.Denomination) + msr.Mintages[i] = y.Mintage + msr.References[i] = y.Reference } xs = append(xs, msr) @@ -162,29 +131,11 @@ func GetMintagesByYear(year int, typ MintageType) (YearMintageData, error) { return zero, err } - rs, err = db.Queryx(` - SELECT * FROM mintages_c - WHERE year = ? AND type = ? - ORDER BY country, mintmark, number + db.SelectContext(context.TODO(), &ys, ` + SELECT * FROM mintages_c + WHERE year = ? and type = ? + ORDER BY country, mintmark, number `, year, typ) - if err != nil { - return zero, err - } - - for rs.Next() { - var y mcRowInternal - if err = rs.StructScan(&y); err != nil { - return zero, err - } - ys = append(ys, MCYearRow{ - Country: y.Country, - Name: y.Name, - Number: y.Number, - Mintmark: sqlOr(y.Mintmark, ""), - Mintage: sqlOr(y.Mintage, MintageUnknown), - Reference: sqlOr(y.Reference, ""), - }) - } return YearMintageData{xs, ys}, nil } @@ -193,10 +144,10 @@ func GetMintagesByCountry(country string, typ MintageType) (CountryMintageData, var ( zero CountryMintageData xs []MSCountryRow - ys []MCCountryRow + ys []MCommemorative ) - rs, err := db.Queryx(` + rs, err := db.QueryxContext(context.TODO(), ` SELECT * FROM mintages_s WHERE country = ? AND type = ? ORDER BY year, mintmark, denomination @@ -206,28 +157,22 @@ func GetMintagesByCountry(country string, typ MintageType) (CountryMintageData, } for rs.Next() { - var x msRowInternal + var x msRow if err = rs.StructScan(&x); err != nil { return zero, err } loop: msr := MSCountryRow{ - Year: x.Year, - Mintmark: sqlOr(x.Mintmark, ""), - References: make([]string, 0, ndenoms), - } - for i := range msr.Mintages { - msr.Mintages[i] = MintageUnknown - } - msr.Mintages[denomToIdx(x.Denomination)] = - sqlOr(x.Mintage, MintageUnknown) - if x.Reference.Valid { - msr.References = append(msr.References, x.Reference.V) + Year: x.Year, + Mintmark: x.Mintmark, } + i := denomToIdx(x.Denomination) + msr.Mintages[i] = x.Mintage + msr.References[i] = x.Reference for rs.Next() { - var y msRowInternal + var y msRow if err = rs.StructScan(&y); err != nil { return zero, err } @@ -238,11 +183,9 @@ func GetMintagesByCountry(country string, typ MintageType) (CountryMintageData, goto loop } - msr.Mintages[denomToIdx(y.Denomination)] = - sqlOr(y.Mintage, MintageUnknown) - if y.Reference.Valid { - msr.References = append(msr.References, y.Reference.V) - } + i = denomToIdx(y.Denomination) + msr.Mintages[i] = y.Mintage + msr.References[i] = y.Reference } xs = append(xs, msr) @@ -252,40 +195,15 @@ func GetMintagesByCountry(country string, typ MintageType) (CountryMintageData, return zero, err } - rs, err = db.Queryx(` - SELECT * FROM mintages_c - WHERE country = ? AND type = ? - ORDER BY year, mintmark, number + db.SelectContext(context.TODO(), &ys, ` + SELECT * FROM mintages_c + WHERE country = ? and type = ? + ORDER BY year, mintmark, number `, country, typ) - if err != nil { - return zero, err - } - - for rs.Next() { - var y mcRowInternal - if err = rs.StructScan(&y); err != nil { - return zero, err - } - ys = append(ys, MCCountryRow{ - Year: y.Year, - Name: y.Name, - Number: y.Number, - Mintmark: sqlOr(y.Mintmark, ""), - Mintage: sqlOr(y.Mintage, MintageUnknown), - Reference: sqlOr(y.Reference, ""), - }) - } return CountryMintageData{xs, ys}, rs.Err() } -func sqlOr[T any](v sql.Null[T], dflt T) T { - if v.Valid { - return v.V - } - return dflt -} - func denomToIdx(d float64) int { return slices.Index([]float64{ 0.01, 0.02, 0.05, 0.10, diff --git a/src/dbx/sql/last.sql b/src/dbx/sql/last.sql index fa2adbb..22ebab8 100644 --- a/src/dbx/sql/last.sql +++ b/src/dbx/sql/last.sql @@ -133,9 +133,25 @@ INSERT INTO mintages_c ( mintage, reference ) VALUES - ('sk', 0, 2014, 'Slovak Republic to the EU', 1, NULL, 1000000, NULL), - ('sk', 0, 2015, 'Ľudovít Štúr', 1, NULL, 1000000, NULL), - ('sk', 0, 2015, 'EU Flag', 2, NULL, 1000000, NULL), - ('fr', 0, 2015, 'Peace and security', 1, NULL, 4000000, NULL), - ('fr', 0, 2015, 'Fête de la Fédération', 2, NULL, 4000000, NULL), - ('fr', 0, 2015, 'EU Flag', 3, NULL, 4000000, NULL);
\ No newline at end of file + ('de', 0, 2015, C_('Hessen', 'CC Name'), 1, 'A', 6000000, NULL), + ('de', 0, 2015, C_('German Reunification', 'CC Name'), 2, 'A', 6000000, NULL), + ('de', 0, 2015, C_('EU Flag', 'CC Name'), 3, 'A', 6000000, NULL), + ('de', 0, 2015, C_('Hessen', 'CC Name'), 1, 'D', 6300000, NULL), + ('de', 0, 2015, C_('German Reunification', 'CC Name'), 2, 'D', 6300000, NULL), + ('de', 0, 2015, C_('EU Flag', 'CC Name'), 3, 'D', 6300000, NULL), + ('de', 0, 2015, C_('Hessen', 'CC Name'), 1, 'F', 7200000, NULL), + ('de', 0, 2015, C_('German Reunification', 'CC Name'), 2, 'F', 7200000, NULL), + ('de', 0, 2015, C_('EU Flag', 'CC Name'), 3, 'F', 7200000, NULL), + ('de', 0, 2015, C_('Hessen', 'CC Name'), 1, 'G', 4200000, NULL), + ('de', 0, 2015, C_('German Reunification', 'CC Name'), 2, 'G', 4200000, NULL), + ('de', 0, 2015, C_('EU Flag', 'CC Name'), 3, 'G', 4200000, NULL), + ('de', 0, 2015, C_('Hessen', 'CC Name'), 1, 'J', 6300000, NULL), + ('de', 0, 2015, C_('German Reunification', 'CC Name'), 2, 'J', 6300000, NULL), + ('de', 0, 2015, C_('EU Flag', 'CC Name'), 3, 'J', 6300000, NULL), + ('sk', 0, 2014, C_('Slovak Republic to the EU', 'CC Name'), 1, NULL, 1000000, NULL), + ('sk', 0, 2015, C_('Ľudovít Štúr', 'CC Name'), 1, NULL, 1000000, NULL), + ('sk', 0, 2015, C_('EU Flag', 'CC Name'), 2, NULL, 1000000, NULL), + ('nl', 0, 2015, C_('EU Flag', 'CC Name'), 2, NULL, NULL, NULL), + ('fr', 0, 2015, C_('Peace and security', 'CC Name'), 1, NULL, 4000000, NULL), + ('fr', 0, 2015, C_('Fête de la Fédération', 'CC Name'), 2, NULL, 4000000, NULL), + ('fr', 0, 2015, C_('EU Flag', 'CC Name'), 3, NULL, 4000000, NULL);
\ No newline at end of file diff --git a/src/dbx/users.go b/src/dbx/users.go index 4235b28..bf78dcd 100644 --- a/src/dbx/users.go +++ b/src/dbx/users.go @@ -1,6 +1,7 @@ package dbx import ( + "context" "database/sql" "errors" @@ -27,7 +28,7 @@ func CreateUser(user User) error { return err } - _, err = db.Exec(` + _, err = db.ExecContext(context.TODO(), ` INSERT INTO users ( email, username, @@ -43,8 +44,8 @@ func Login(username, password string) (User, error) { username = norm.NFC.String(username) password = norm.NFC.String(password) - /* TODO: Pass a context here? */ - rs, err := db.Queryx(`SELECT * FROM users WHERE username = ?`, username) + rs, err := db.QueryxContext(context.TODO(), + `SELECT * FROM users WHERE username = ?`, username) if err != nil { return User{}, err } diff --git a/src/http.go b/src/http.go index 071b25c..fce82ba 100644 --- a/src/http.go +++ b/src/http.go @@ -13,8 +13,6 @@ import ( "strings" "time" - "golang.org/x/text/collate" - "golang.org/x/text/language" . "git.thomasvoss.com/euro-cash.eu/pkg/try" "git.thomasvoss.com/euro-cash.eu/src/dbx" @@ -155,7 +153,6 @@ func mintageHandler(next http.Handler) http.Handler { td.FilterBy = "country" } - var err error mt := dbx.NewMintageType(td.Type) switch td.FilterBy { @@ -166,45 +163,25 @@ func mintageHandler(next http.Handler) http.Handler { }) { td.Code = td.Countries[0].Code } - td.CountryMintages, err = dbx.GetMintagesByCountry(td.Code, mt) + + m, err := dbx.GetMintagesByCountry(td.Code, mt) + if err != nil { + throwError(http.StatusInternalServerError, err, w, r) + return + } + td.CountryMintages = makeCountryMintageTable(m, td.Printer) case "year": + var err error td.Year, err = strconv.Atoi(r.FormValue("year")) - if err != nil { + if err != nil || td.Year < 1999 { td.Year = 1999 } - td.YearMintages, err = dbx.GetMintagesByYear(td.Year, mt) - - /* NOTE: It’s safe to use MustParse() here, because by this - point we know that all BCPs are valid. */ - c := collate.New(language.MustParse(td.Printer.Bcp)) - for i, r := range td.YearMintages.Standard { - name := td.Printer.GetC( - countryCodeToName[r.Country], "Place Name") - td.YearMintages.Standard[i].Country = name - } - for i, r := range td.YearMintages.Commemorative { - name := td.Printer.GetC( - countryCodeToName[r.Country], "Place Name") - td.YearMintages.Commemorative[i].Country = name + m, err := dbx.GetMintagesByYear(td.Year, mt) + if err != nil { + throwError(http.StatusInternalServerError, err, w, r) + return } - slices.SortFunc(td.YearMintages.Standard, func(x, y dbx.MSYearRow) int { - Δ := c.CompareString(x.Country, y.Country) - if Δ == 0 { - Δ = c.CompareString(x.Mintmark, y.Mintmark) - } - return Δ - }) - slices.SortFunc(td.YearMintages.Commemorative, func(x, y dbx.MCYearRow) int { - Δ := c.CompareString(x.Country, y.Country) - if Δ == 0 { - Δ = c.CompareString(x.Mintmark, y.Mintmark) - } - return Δ - }) - } - if err != nil { - throwError(http.StatusInternalServerError, err, w, r) - return + td.YearMintages = makeYearMintageTable(m, td.Printer) } next.ServeHTTP(w, r) diff --git a/src/tables.go b/src/tables.go new file mode 100644 index 0000000..f99630b --- /dev/null +++ b/src/tables.go @@ -0,0 +1,108 @@ +package app + +import ( + "database/sql" + "slices" + + "golang.org/x/text/collate" + "golang.org/x/text/language" + + "git.thomasvoss.com/euro-cash.eu/src/dbx" + "git.thomasvoss.com/euro-cash.eu/src/i18n" +) + +type YearCCsPair struct { + Year int + Mintmark sql.Null[string] + CCs []dbx.MCommemorative +} + +type CountryMintageTable struct { + Standard []dbx.MSCountryRow + Commemorative []YearCCsPair +} + +type CountryCCsPair struct { + Country string + Mintmark sql.Null[string] + CCs []dbx.MCommemorative +} + +type YearMintageTable struct { + Standard []dbx.MSYearRow + Commemorative []CountryCCsPair +} + +func makeCountryMintageTable(data dbx.CountryMintageData, p i18n.Printer) CountryMintageTable { + ccdata := data.Commemorative + ccs := make([]YearCCsPair, 0, len(ccdata)) + + for len(ccdata) > 0 { + x := ccdata[0] + i := len(ccdata) + for j, y := range ccdata[1:] { + if x.Year != y.Year || x.Mintmark != y.Mintmark { + i = j + 1 + break + } + } + ccs = append(ccs, YearCCsPair{ + Year: x.Year, + Mintmark: x.Mintmark, + CCs: ccdata[:i], + }) + ccdata = ccdata[i:] + } + + return CountryMintageTable{data.Standard, ccs} +} + +func makeYearMintageTable(data dbx.YearMintageData, p i18n.Printer) YearMintageTable { + ccdata := data.Commemorative + ccs := make([]CountryCCsPair, 0, len(ccdata)) + + for len(ccdata) > 0 { + x := ccdata[0] + i := len(ccdata) + for j, y := range ccdata[1:] { + if x.Country != y.Country || x.Mintmark != y.Mintmark { + i = j + 1 + break + } + } + ccs = append(ccs, CountryCCsPair{ + Country: x.Country, + Mintmark: x.Mintmark, + CCs: ccdata[:i], + }) + ccdata = ccdata[i:] + } + + /* NOTE: It’s safe to use MustParse() here, because by this + point we know that all BCPs are valid. */ + c := collate.New(language.MustParse(p.Bcp)) + for i, r := range data.Standard { + name := countryCodeToName[r.Country] + data.Standard[i].Country = p.GetC(name, "Place Name") + } + for i, r := range ccs { + name := countryCodeToName[r.Country] + ccs[i].Country = p.GetC(name, "Place Name") + } + slices.SortFunc(data.Standard, func(x, y dbx.MSYearRow) int { + Δ := c.CompareString(x.Country, y.Country) + if Δ == 0 { + Δ = c.CompareString(x.Mintmark.V, y.Mintmark.V) + } + return Δ + }) + slices.SortFunc(ccs, func(x, y CountryCCsPair) int { + Δ := c.CompareString(x.Country, y.Country) + if Δ == 0 { + Δ = c.CompareString(x.Mintmark.V, y.Mintmark.V) + } + return Δ + }) + + return YearMintageTable{data.Standard, ccs} +} diff --git a/src/templates.go b/src/templates.go index 076f8dc..6a43fcb 100644 --- a/src/templates.go +++ b/src/templates.go @@ -10,7 +10,6 @@ import ( . "git.thomasvoss.com/euro-cash.eu/pkg/try" "git.thomasvoss.com/euro-cash.eu/pkg/watch" - "git.thomasvoss.com/euro-cash.eu/src/dbx" "git.thomasvoss.com/euro-cash.eu/src/i18n" ) @@ -20,8 +19,8 @@ type templateData struct { Printers map[string]i18n.Printer Code, Type, FilterBy string Year int - CountryMintages dbx.CountryMintageData - YearMintages dbx.YearMintageData + CountryMintages CountryMintageTable + YearMintages YearMintageTable Countries []country } @@ -30,6 +29,7 @@ var ( errorTmpl *template.Template templates map[string]*template.Template funcmap = map[string]any{ + "evenp": evenp, "ifElse": ifElse, "locales": i18n.Locales, "map": templateMakeMap, @@ -132,6 +132,10 @@ func templateMakeMap(args ...any) map[string]any { return m } +func evenp(n int) bool { + return n&1 == 0 +} + func ifElse(b bool, x, y any) any { if b { return x diff --git a/src/templates/-base.html.tmpl b/src/templates/-base.html.tmpl index f455a14..2e78a7c 100644 --- a/src/templates/-base.html.tmpl +++ b/src/templates/-base.html.tmpl @@ -14,22 +14,32 @@ const $$ = q => document.querySelectorAll(q); (() => { - const validate = theme => - ["light", "dark"].includes(theme) ? theme : "light"; - const toggle = theme => - theme == "light" ? "dark" : "light"; + document.addEventListener("DOMContentLoaded", _ => { + const root = $("html"); + const icons = { + light: $("#nav-icon-theme-light"), + dark: $("#nav-icon-theme-dark"), + }; - const setTheme = theme => { - localStorage.setItem("theme", theme); - $("html").setAttribute("data-theme", theme); - $(`#nav-icon-theme-${theme}`).style.display = ""; - $(`#nav-icon-theme-${toggle(theme)}`).style.display = "none"; - }; + const toggle = theme => + theme === "light" ? "dark" : "light" - document.addEventListener("DOMContentLoaded", _ => { - $("#theme-button").onclick = () => - setTheme(toggle(validate(localStorage.getItem("theme")))); - setTheme(validate(localStorage.getItem("theme"))); + const setTheme = theme => { + localStorage.setItem("theme", theme); + root.setAttribute("data-theme", theme); + icons[theme].style.display = ""; + icons[toggle(theme)].style.display = "none"; + }; + + /* Double toggle to handle invalid theme */ + setTheme(toggle(toggle(localStorage.getItem("theme")))); + $("#theme-button").onclick = () => { + const theme = toggle(localStorage.getItem("theme")); + if (document.startViewTransition) + document.startViewTransition(() => setTheme(theme)); + else + setTheme(theme); + }; }); })(); </script> diff --git a/src/templates/coins-mintages.html.tmpl b/src/templates/coins-mintages.html.tmpl index 7c041f3..e5fa5f1 100644 --- a/src/templates/coins-mintages.html.tmpl +++ b/src/templates/coins-mintages.html.tmpl @@ -9,6 +9,10 @@ position: sticky; left: 0; } + + .striped :is(th, td) { + background-color: var(--pico-table-row-stripped-background-color); + } } label[for="country-dd"] { display: none; } @@ -99,11 +103,12 @@ </div> <button type="submit">{{ .GetC "Filter" "Header/Label" }}</button> </form> + + {{ if and (eq .FilterBy "country") + (gt (len .CountryMintages.Standard) 0) }} <figure> <figcaption>{{ .Get "Standard Issue Coins" }}</figcaption> <div class="overflow-auto"> - {{ if eq .FilterBy "country" }} - <table class="mintage-table striped" role="grid"> <thead> <th>{{ .GetC "Year" "Header/Label" }}</th> @@ -122,8 +127,8 @@ <tr> <th scope="row"> {{- .Year -}} - {{- if ne .Mintmark "" -}} - <sub><small>{{ .Mintmark }}</small></sub> + {{- if .Mintmark.Valid -}} + <sub><small>{{ .Mintmark.V }}</small></sub> {{- end -}} </th> {{ range .Mintages }} @@ -133,9 +138,15 @@ {{ end }} </tbody> </table> + </div> + </figure> - {{ else if eq .FilterBy "year" }} + {{ else if and (eq .FilterBy "year") + (gt (len .YearMintages.Standard) 0) }} + <figure> + <figcaption>{{ .Get "Standard Issue Coins" }}</figcaption> + <div class="overflow-auto"> <table class="mintage-table striped" role="grid"> <thead> <th>{{ .GetC "Country" "Header/Label" }}</th> @@ -154,8 +165,8 @@ <tr> <th scope="row"> {{- .Country -}} - {{- if ne .Mintmark "" -}} - <sub><small>{{ .Mintmark }}</small></sub> + {{- if .Mintmark.Valid -}} + <sub><small>{{ .Mintmark.V }}</small></sub> {{- end -}} </th> {{ range .Mintages }} @@ -165,15 +176,15 @@ {{ end }} </tbody> </table> - {{ end }} </div> </figure> + {{ end }} {{ if eq .FilterBy "country" }} {{ if ne (len .CountryMintages.Commemorative) 0 }} <figure> <figcaption>{{ .Get "Commemorative Coins" }}</figcaption> - <table class="mintage-table striped" role="grid"> + <table class="mintage-table" role="grid"> <thead> <th>{{ .GetC "Year" "Header/Label" }}</th> <th>{{ .GetC "Commemorated Topic" "Header/Label" }}</th> @@ -181,21 +192,25 @@ </thead> <tbody> {{ $p := .Printer }} - {{ range .CountryMintages.Commemorative }} - <tr> - <th scope="row"> - {{- .Year -}} - {{- if ne .Mintmark "" -}} - <sub><small>{{ .Mintmark }}</small></sub> + {{ range $i, $ := .CountryMintages.Commemorative }} + {{ $y := .Year }} + {{ $mm := .Mintmark }} + {{ $ccs := .CCs }} + {{ range $j, $cc := .CCs }} + <tr {{ if evenp $i }}class="striped"{{ end }}> + {{ if eq $j 0 }} + <th scope="row" rowspan="{{ len $ccs }}"> + {{- $y -}} + {{- if $mm.Valid -}} + <sub><small>{{ $mm.V }}</small></sub> {{- end -}} </th> - <!-- TODO: Translate commemorative names --> - <td>{{ .Name }}</td> - {{ with .Mintage }} - {{ template "mintages/mintage-cell" (tuple . $p) }} {{ end }} + <td>{{ $p.GetC .Name "CC Name" }}</td> + {{ template "mintages/mintage-cell" (tuple .Mintage $p) }} </tr> {{ end }} + {{ end }} </tbody> </table> </figure> @@ -206,7 +221,7 @@ {{ if ne (len .YearMintages.Commemorative) 0 }} <figure> <figcaption>{{ .Get "Commemorative Coins" }}</figcaption> - <table class="mintage-table striped" role="grid"> + <table class="mintage-table" role="grid"> <thead> <th>{{ .GetC "Country" "Header/Label" }}</th> <th>{{ .GetC "Commemorated Topic" "Header/Label" }}</th> @@ -214,21 +229,25 @@ </thead> <tbody> {{ $p := .Printer }} - {{ range .YearMintages.Commemorative }} - <tr> - <th scope="row"> - {{- .Country -}} - {{- if ne .Mintmark "" -}} - <sub><small>{{ .Mintmark }}</small></sub> + {{ range $i, $ := .YearMintages.Commemorative }} + {{ $c := .Country }} + {{ $mm := .Mintmark }} + {{ $ccs := .CCs }} + {{ range $j, $cc := .CCs }} + <tr {{ if evenp $i }}class="striped"{{ end }}> + {{ if eq $j 0 }} + <th scope="row" rowspan="{{ len $ccs }}"> + {{- $c -}} + {{- if $mm.Valid -}} + <sub><small>{{ $mm.V }}</small></sub> {{- end -}} </th> - <!-- TODO: Translate commemorative names --> - <td>{{ .Name }}</td> - {{ with .Mintage }} - {{ template "mintages/mintage-cell" (tuple . $p) }} {{ end }} + <td>{{ $p.GetC .Name "CC Name" }}</td> + {{ template "mintages/mintage-cell" (tuple .Mintage $p) }} </tr> {{ end }} + {{ end }} </tbody> </table> </figure> @@ -271,13 +290,11 @@ {{ define "mintages/mintage-cell" }} {{ $v := index . 0 }} {{ $p := index . 1 }} -{{ if eq $v -1 }} - <td data-numeric>{{ $p.Get "Unknown" }}</td> -{{ else if eq $v -2 }} - <td data-numeric class="error">{{ $p.Get "Error" }}</td> -{{ else if eq $v 0 }} +{{ if not $v.Valid }} + <td data-numeric>{{ $p.GetC "Unknown" "Header/Label" }}</td> +{{ else if eq $v.V 0 }} <td data-numeric>—</td> {{ else }} - <td data-numeric>{{ $p.Itoa $v }}</td> -{{ end }} + <td data-numeric>{{ $p.Itoa $v.V }}</td> {{ end }} +{{ end }}
\ No newline at end of file |