diff --git a/dbmodels/collectionhelper.go b/dbmodels/collectionhelper.go
new file mode 100644
index 0000000..b379523
--- /dev/null
+++ b/dbmodels/collectionhelper.go
@@ -0,0 +1,126 @@
+package dbmodels
+
+import (
+ "encoding/json"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// CollectionInfo holds only the ID, a list of single references, and the Recorded flag.
+type CollectionInfo struct {
+ Collection *Content
+ Singles []int
+ Recorded bool
+}
+
+func (ci CollectionInfo) String() string {
+ marshalled, _ := json.Marshal(ci)
+ return string(marshalled)
+}
+
+// parseAnnotation detects "nicht erfasst" references (Recorded=false),
+// then finds all "INr" references (both single values and ranges).
+// Ranges like "100-105" are fully expanded to singles. Duplicates are removed.
+// Any references not in `inos` are ignored.
+func ParseAnnotation(c *Content, annotation string, inos []int) CollectionInfo {
+ ci := CollectionInfo{
+ Collection: c,
+ Singles: []int{},
+ Recorded: true, // Default
+ }
+
+ // 1) Detect phrases like "nicht erfasst", "nicht aufgenommen", etc.
+ notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"}
+ lowerAnn := strings.ToLower(annotation)
+ if strings.Contains(lowerAnn, "nicht") {
+ for _, kw := range notRecordedPatterns {
+ if strings.Contains(lowerAnn, kw) {
+ ci.Recorded = false
+ break
+ }
+ }
+ }
+
+ // We'll keep singles in a map for deduplication
+ singlesMap := make(map[int]struct{})
+
+ // 2) Regex that matches "INr" plus the numeric portion (including dash / punctuation).
+ re := regexp.MustCompile(`(?i)\bINr[.:]?\s+([\d,\-\s–—;/.]+)`)
+ matches := re.FindAllStringSubmatch(annotation, -1)
+
+ // Regex to unify different dash characters into a simple '-'
+ dashRegex := regexp.MustCompile(`[–—−‒]`)
+
+ // Helper to expand a range, e.g. 10615–10621 => 10615..10621
+ expandRange := func(fromVal, toVal int) {
+ // If reversed, its a typo
+ if fromVal > toVal {
+ return
+ }
+ for v := fromVal; v <= toVal; v++ {
+ if inList(v, inos) {
+ singlesMap[v] = struct{}{}
+ }
+ }
+ }
+
+ for _, m := range matches {
+ numericChunk := m[1]
+
+ // Replace typographic dashes with ASCII hyphen
+ numericChunk = dashRegex.ReplaceAllString(numericChunk, "-")
+
+ // Also unify semicolons or slashes to commas
+ extraDelims := regexp.MustCompile(`[;/]+`)
+ numericChunk = extraDelims.ReplaceAllString(numericChunk, ",")
+
+ // Now split on commas
+ parts := strings.Split(numericChunk, ",")
+ for _, p := range parts {
+ p = strings.TrimSpace(p)
+ if p == "" {
+ continue
+ }
+ // If we see a hyphen, treat it as a range
+ if strings.Contains(p, "-") {
+ rangeParts := strings.SplitN(p, "-", 2)
+ if len(rangeParts) == 2 {
+ fromStr := strings.TrimSpace(rangeParts[0])
+ toStr := strings.TrimSpace(rangeParts[1])
+ if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil {
+ if toVal, errTo := strconv.Atoi(toStr); errTo == nil {
+ expandRange(fromVal, toVal)
+ }
+ }
+ }
+ } else {
+ // Single integer reference
+ if val, err := strconv.Atoi(p); err == nil {
+ if inList(val, inos) {
+ singlesMap[val] = struct{}{}
+ }
+ }
+ }
+ }
+ }
+
+ // Flatten the map into a sorted slice
+ for s := range singlesMap {
+ ci.Singles = append(ci.Singles, s)
+ }
+ sort.Ints(ci.Singles)
+
+ return ci
+}
+
+// inList checks membership in `inos`
+func inList(x int, list []int) bool {
+ for _, item := range list {
+ if item == x {
+ return true
+ }
+ }
+ return false
+}
diff --git a/dbmodels/content.go b/dbmodels/content.go
index 3fe9d8a..077616e 100644
--- a/dbmodels/content.go
+++ b/dbmodels/content.go
@@ -157,6 +157,14 @@ func (c *Content) SetScans(scans []*filesystem.File) {
c.Set(SCAN_FIELD, scans)
}
+func (r *Content) ImagePaths() []string {
+ ret := []string{}
+ for _, s := range r.Scans() {
+ ret = append(ret, "/api/files/"+r.TableName()+"/"+r.Id+"/"+s)
+ }
+ return ret
+}
+
func (c *Content) Numbering() float64 {
return c.GetFloat(NUMBERING_FIELD)
}
diff --git a/dbmodels/sorting.go b/dbmodels/sorting.go
index 3f876f3..ec19712 100644
--- a/dbmodels/sorting.go
+++ b/dbmodels/sorting.go
@@ -3,6 +3,7 @@ package dbmodels
import (
"slices"
+ "github.com/Theodor-Springmann-Stiftung/musenalm/helpers/datatypes"
"golang.org/x/text/collate"
"golang.org/x/text/language"
)
@@ -41,3 +42,9 @@ func Sort_REntriesSeries_Year(entries []*REntriesSeries, entriesMap map[string]*
return ientry.Year() - jentry.Year()
})
}
+
+func Sort_Contents_Numbering(contents []*Content) {
+ slices.SortFunc(contents, func(i, j *Content) int {
+ return datatypes.CompareFloat(i.Numbering(), j.Numbering())
+ })
+}
diff --git a/helpers/datatypes/float64.go b/helpers/datatypes/float64.go
new file mode 100644
index 0000000..0214136
--- /dev/null
+++ b/helpers/datatypes/float64.go
@@ -0,0 +1,15 @@
+package datatypes
+
+import "math"
+
+const float64EqualityThreshold = 1e-9
+
+func CompareFloat(a, b float64) int {
+ if math.Abs(a-b) < float64EqualityThreshold {
+ return 0
+ }
+ if a < b {
+ return -1
+ }
+ return 1
+}
diff --git a/helpers/functions/string.go b/helpers/functions/string.go
index b5ac6fb..045101f 100644
--- a/helpers/functions/string.go
+++ b/helpers/functions/string.go
@@ -1,13 +1,17 @@
package functions
import (
+ "fmt"
"html/template"
+ "regexp"
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
+var linksexp = regexp.MustCompile(`INr\s*([0-9]+)(?:\s*[-,;]\s*[0-9]*)*\s*(?:,|;)?\s*(?:obj|Obj)?\s*[0-9]*(?:\s*[-,;]\s*[0-9]*)*`)
+
func Safe(s string) template.HTML {
if len(s) == 0 {
return ""
@@ -39,3 +43,15 @@ func First(s string) string {
return string(r[0])
}
+
+func LinksAnnotation(s string) string {
+ annotation := linksexp.ReplaceAllStringFunc(s, func(match string) string {
+ submatches := linksexp.FindStringSubmatch(match)
+ if len(submatches) > 1 {
+ return fmt.Sprintf(`%s`, submatches[1], match)
+ }
+ return match
+ })
+
+ return annotation
+}
diff --git a/pages/almanach.go b/pages/almanach.go
index dae3dfd..1dcf78f 100644
--- a/pages/almanach.go
+++ b/pages/almanach.go
@@ -72,6 +72,9 @@ type AlmanachResult struct {
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
EntriesAgents []*dbmodels.REntriesAgents
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
+
+ CInfoByCollection map[string]dbmodels.CollectionInfo
+ CInfoByContent map[int][]dbmodels.CollectionInfo
}
func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
@@ -110,6 +113,8 @@ func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
return nil, err
}
+ dbmodels.Sort_Contents_Numbering(contents)
+
contentsagents, err := dbmodels.RContentsAgents_Contents(app, dbmodels.Ids(contents))
caids := []any{}
caMap := map[string][]*dbmodels.RContentsAgents{}
@@ -137,7 +142,7 @@ func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
agentsMap[a.Id] = a
}
- return &AlmanachResult{
+ ret := &AlmanachResult{
Entry: entry,
Places: places,
Series: series,
@@ -146,6 +151,35 @@ func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
EntriesSeries: srelationsMap,
EntriesAgents: entriesagents,
ContentsAgents: caMap,
- }, nil
+ }
+
+ ret.Collections()
+ return ret, nil
}
+
+func (r *AlmanachResult) Collections() {
+ ids := []int{}
+ collections := []*dbmodels.Content{}
+ for _, s := range r.Contents {
+ ids = append(ids, s.MusenalmID())
+ for _, t := range s.MusenalmType() {
+ if t == "Sammlung" {
+ collections = append(collections, s)
+ }
+ }
+ }
+
+ ccontentcollectionmap := map[int][]dbmodels.CollectionInfo{}
+ ccollectioncontentmap := map[string]dbmodels.CollectionInfo{}
+ for _, v := range collections {
+ cinfo := dbmodels.ParseAnnotation(v, v.Annotation(), ids)
+ ccollectioncontentmap[v.Id] = cinfo
+ for _, c := range cinfo.Singles {
+ ccontentcollectionmap[c] = append(ccontentcollectionmap[c], cinfo)
+ }
+ }
+
+ r.CInfoByCollection = ccollectioncontentmap
+ r.CInfoByContent = ccontentcollectionmap
+}
diff --git a/pages/contents.go b/pages/contents.go
new file mode 100644
index 0000000..5904a63
--- /dev/null
+++ b/pages/contents.go
@@ -0,0 +1,10 @@
+package pages
+
+type ContentListFilterParams struct {
+ Agent string
+ Type string
+ Page int
+ OnlyScans bool
+ AlmNumber int
+ Entry string
+}
diff --git a/templating/engine.go b/templating/engine.go
index 350fdad..e116610 100644
--- a/templating/engine.go
+++ b/templating/engine.go
@@ -130,6 +130,7 @@ func (e *Engine) funcs() error {
e.AddFunc("First", functions.First)
e.AddFunc("ReplaceSlashParen", functions.ReplaceSlashParen)
e.AddFunc("ReplaceSlashParenSlash", functions.ReplaceSlashParenSlash)
+ e.AddFunc("LinksAnnotation", functions.LinksAnnotation)
// Time & Date Functions
e.AddFunc("Today", functions.Today)
diff --git a/views/routes/almanach/body.gohtml b/views/routes/almanach/body.gohtml
index 9761068..5fd423c 100644
--- a/views/routes/almanach/body.gohtml
+++ b/views/routes/almanach/body.gohtml
@@ -2,6 +2,8 @@
{{/* .result:
type AlmanachResult struct {
Entry *dbmodels.Entry
+ Agent *dbmodels.Agent
+ Entries map[string]*dbmodels.Entry
Places []*dbmodels.Place
Series []*dbmodels.Series
Contents []*dbmodels.Content
@@ -9,11 +11,23 @@
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
EntriesAgents []*dbmodels.REntriesAgents
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
+
+
+ CInfoByCollection map[string]*dbmodels.CollectionInfo
+ CInfoByContent map[int][]*dbmodels.CollectionInfo
}
-*/}}
-{{ $isGer := false }}
-{{ $isFra := false }}
-{{ $isEng := false }}
+
+
+ .parameters {
+ Sort string
+ MusenalmID string
+ PersonFilter string
+ TitleFilter string
+ EntryFilter string
+ TypeFilter []string
+ Scanfilter bool
+ }
+ */}}
@@ -44,175 +58,15 @@
{{- end -}}
-
-
Almanach
-
-
-
-
-
-
-
Almanach-Nummer
-
{{ $model.result.Entry.MusenalmID }}
-
- {{- if $model.result.Entry.PreferredTitle -}}
-
-
Kurztitel
-
{{ $model.result.Entry.PreferredTitle }}
-
- {{- end -}}
- {{- if $model.result.Entry.TitleStmt -}}
-
-
Titel
-
{{ $model.result.Entry.TitleStmt }}
-
- {{- end -}}
-
- {{- if $model.result.Entry.ResponsibilityStmt -}}
-
-
Herausgeberangabe
-
{{ $model.result.Entry.ResponsibilityStmt }}
-
- {{- end -}}
- {{- if $model.result.Entry.Extent -}}
-
- {{- end -}}
- {{- if $model.result.Entry.Language -}}
-
-
Sprache
-
- {{- range $i, $lang := $model.result.Entry.Language -}}
- {{- if $i -}},{{- end -}}
- {{- if eq $lang "ger" -}}
- {{ $isGer = true }}
- Deutsch
- {{- else if eq $lang "eng" -}}
- {{ $isEng = true }}
- Englisch
- {{- else if eq $lang "fre" -}}
- {{ $isFra = true }}
- Französisch
- {{- else if eq $lang "ita" -}}
- Italienisch
- {{- else if eq $lang "lat" -}}
- Latein
- {{- else -}}
- {{ $lang }}
- {{- end -}}
- {{- end -}}
-
-
- {{- end -}}
- {{- if $model.result.Entry.References -}}
-
-
Nachweise
-
- {{- $model.result.Entry.References -}}
-
-
- {{- end -}}
- {{- if $model.result.Series -}}
-
-
Reihen
-
- {{- range $i, $s := $model.result.Series -}}
-
- {{- $rel := index $model.result.EntriesSeries $s.Id -}}
- {{- if $rel -}}
- {{- if not (eq $rel.Type "Bevorzugter Reihentitel") -}}
-
- {{- if eq $rel.Type "Früherer Reihentitel" -}}
- hat Titelauflage s.a.
- {{- else if eq $rel.Type "Späterer Reihentitel" -}}
- ist Titelauflage von, s.a.
- {{- else if eq $rel.Type "In anderer Sprache" -}}
- {{- if $isFra -}}
- In deutscher Sprache s.a.
- {{- else -}}
- In französischer Sprache s.a.
- {{- end -}}
- {{- else if eq $rel.Type "Alternatives Titelblatt" -}}
- alternatives Titelblatt, s.a.
- {{- end -}}
-
- {{- end -}}
- {{- end -}}
-
{{ $s.Title }}
-
- {{- end -}}
-
-
- {{- end -}}
- {{- if $model.result.Places -}}
-
-
Orte
-
- {{- range $i, $p := $model.result.Places -}}
-
- {{- end -}}
-
-
- {{- end -}}
- {{- if $model.result.EntriesAgents -}}
-
-
Personen
-
- {{- range $i, $r := $model.result.EntriesAgents -}}
- {{- $a := index $model.result.Agents $r.Agent -}}
- {{- if $a -}}
-
- {{- end -}}
- {{- end -}}
-
-
- {{- end -}}
- {{- if $model.result.Entry.Annotation -}}
-
-
Anmerkungen
-
- {{- Safe (ReplaceSlashParen $model.result.Entry.Annotation) -}}
-
-
- {{- end -}}
-
-
-
-
+{{ template "entrydata" $model }}
-
+
+ {{- range $i, $c := $model.result.Contents -}}
+ {{- $rels := index $model.result.ContentsAgents $c.Id -}}
+ {{- $coll := index $model.result.CInfoByContent $c.MusenalmID -}}
+ {{- if and $coll (index $coll 0) -}}
+ {{- end -}}
+ {{- template "_content" Arr $c $model.result.Entry $rels $model.result.Agents -}}
+ {{- end -}}
diff --git a/views/routes/almanach/components/entrydata.gohtml b/views/routes/almanach/components/entrydata.gohtml
new file mode 100644
index 0000000..f9222c7
--- /dev/null
+++ b/views/routes/almanach/components/entrydata.gohtml
@@ -0,0 +1,188 @@
+{{ $model := . }}
+{{/* .result:
+ type AlmanachResult struct {
+ Entry *dbmodels.Entry
+ Places []*dbmodels.Place
+ Series []*dbmodels.Series
+ Contents []*dbmodels.Content
+ Agents map[string]*dbmodels.Agent // <- Key is agent id
+ EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
+ EntriesAgents []*dbmodels.REntriesAgents
+ ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
+ }
+*/}}
+{{ $isGer := false }}
+{{ $isFra := false }}
+{{ $isEng := false }}
+
+
+
+
Almanach
+
+
+
+
+
+
Almanach-Nummer
+
{{ $model.result.Entry.MusenalmID }}
+
+ {{- if $model.result.Entry.PreferredTitle -}}
+
+
Kurztitel
+
{{ $model.result.Entry.PreferredTitle }}
+
+ {{- end -}}
+ {{- if $model.result.Entry.TitleStmt -}}
+
+
Titel
+
{{ $model.result.Entry.TitleStmt }}
+
+ {{- end -}}
+
+ {{- if $model.result.Entry.ResponsibilityStmt -}}
+
+
Herausgeberangabe
+
{{ $model.result.Entry.ResponsibilityStmt }}
+
+ {{- end -}}
+ {{- if $model.result.Entry.Extent -}}
+
+ {{- end -}}
+ {{- if $model.result.Entry.Language -}}
+
+
Sprache
+
+ {{- range $i, $lang := $model.result.Entry.Language -}}
+ {{- if $i -}},{{- end -}}
+ {{- if eq $lang "ger" -}}
+ {{ $isGer = true }}
+ Deutsch
+ {{- else if eq $lang "eng" -}}
+ {{ $isEng = true }}
+ Englisch
+ {{- else if eq $lang "fre" -}}
+ {{ $isFra = true }}
+ Französisch
+ {{- else if eq $lang "ita" -}}
+ Italienisch
+ {{- else if eq $lang "lat" -}}
+ Latein
+ {{- else -}}
+ {{ $lang }}
+ {{- end -}}
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- if $model.result.Entry.References -}}
+
+
Nachweise
+
+ {{- $model.result.Entry.References -}}
+
+
+ {{- end -}}
+ {{- if $model.result.Series -}}
+
+
Reihen
+
+ {{- range $i, $s := $model.result.Series -}}
+
+ {{- $rel := index $model.result.EntriesSeries $s.Id -}}
+ {{- if $rel -}}
+ {{- if not (eq $rel.Type "Bevorzugter Reihentitel") -}}
+
+ {{- if eq $rel.Type "Früherer Reihentitel" -}}
+ hat Titelauflage s.a.
+ {{- else if eq $rel.Type "Späterer Reihentitel" -}}
+ ist Titelauflage von, s.a.
+ {{- else if eq $rel.Type "In anderer Sprache" -}}
+ {{- if $isFra -}}
+ In deutscher Sprache s.a.
+ {{- else -}}
+ In französischer Sprache s.a.
+ {{- end -}}
+ {{- else if eq $rel.Type "Alternatives Titelblatt" -}}
+ alternatives Titelblatt, s.a.
+ {{- end -}}
+
+ {{- end -}}
+ {{- end -}}
+
{{ $s.Title }}
+
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- if $model.result.Places -}}
+
+
Orte
+
+ {{- range $i, $p := $model.result.Places -}}
+
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- if $model.result.EntriesAgents -}}
+
+
Personen
+
+ {{- range $i, $r := $model.result.EntriesAgents -}}
+ {{- $a := index $model.result.Agents $r.Agent -}}
+ {{- if $a -}}
+
+ {{- end -}}
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- if $model.result.Entry.Annotation -}}
+
+
Anmerkungen
+
+ {{- Safe (ReplaceSlashParen $model.result.Entry.Annotation) -}}
+
+
+ {{- end -}}
+
+
+
+
+
+
diff --git a/views/routes/components/_content.gohtml b/views/routes/components/_content.gohtml
new file mode 100644
index 0000000..8be7baa
--- /dev/null
+++ b/views/routes/components/_content.gohtml
@@ -0,0 +1,118 @@
+{{ $model := . }}
+{{/* .1 - *Content
+ .2 - *Entry
+ .3 - []*RContentsAgents
+ .4 - map[string]*Agent
+*/}}
+
+{{- $content := index . 0 -}}
+{{- $entry := index . 1 -}}
+{{- $rcas := index . 2 -}}
+{{- $agents := index . 3 -}}
+
+
+
+
+ {{- if $content.Extent -}}
+
+ S.
+ {{- $content.Extent -}}
+
+ {{- end -}}
+ {{- if $content.MusenalmType -}}
+
+ {{- range $_, $t := $content.MusenalmType -}}
+
+ {{- $t -}}
+
+ {{- end -}}
+
+ {{- end -}}
+
+
+
+
+
+ {{- if $content.TitleStmt -}}
+
Titel
+
{{- $content.TitleStmt -}}
+ {{- end -}}
+ {{- if $content.IncipitStmt -}}
+
Incipit
+
{{ $content.IncipitStmt }}…
+ {{- end -}}
+ {{- if $content.ResponsibilityStmt -}}
+
Autorangabe
+
{{- $content.ResponsibilityStmt -}}
+ {{- end -}}
+ {{- if $rcas -}}
+
Personen
+
+ {{- range $_, $rca := $rcas -}}
+
+ {{- $agent := index $agents $rca.Agent -}}
+ {{- if $agent -}}
+
+
{{- $agent.Name -}}
+ ({{ $agent.BiographicalData -}})
+
+ {{- end -}}
+
+ {{- end -}}
+
+ {{- end -}}
+ {{- if $content.Annotation -}}
+
Anmerkung
+
+ {{- Safe (LinksAnnotation (ReplaceSlashParen
+ $content.Annotation))
+ -}}
+
+ {{- end -}}
+
+
+
+ {{- $scans := $content.ImagePaths -}}
+ {{- $slen := len $scans -}}
+ {{- $double := false -}}
+ {{- if gt $slen 2 -}}
+ {{- $double = true -}}
+ {{- end -}}
+
+ {{- if $scans -}}
+
+ {{- range $_, $scan := $scans -}}
+
+
+
+
+
+ {{- end -}}
+
+ {{- end -}}
+
+
+
+
+ NR
+ {{ $content.MusenalmID -}}
+
+
+
+
diff --git a/views/routes/components/_contentlist.gohtml b/views/routes/components/_contentlist.gohtml
new file mode 100644
index 0000000..bbf0abc
--- /dev/null
+++ b/views/routes/components/_contentlist.gohtml
@@ -0,0 +1,23 @@
+{{ $model := . }}
+{{/* .result:
+ type AlmanachResult struct {
+ Entry *dbmodels.Entry
+ Places []*dbmodels.Place
+ Series []*dbmodels.Series
+ Contents []*dbmodels.Content
+ Agents map[string]*dbmodels.Agent // <- Key is agent id
+ EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
+ EntriesAgents []*dbmodels.REntriesAgents
+ ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
+ }
+
+ .parameters {
+ Sort string
+ MusenalmID string
+ PersonFilter string
+ TitleFilter string
+ EntryFilter string
+ TypeFilter []string
+ Scanfilter bool
+ }
+ */}}
diff --git a/views/transform/main.js b/views/transform/main.js
index d3deab8..cded9f3 100644
--- a/views/transform/main.js
+++ b/views/transform/main.js
@@ -15,6 +15,7 @@ const SCROLL_BUTTON_ELEMENT = "scroll-button";
const TOOLTIP_ELEMENT = "tool-tip";
const ABBREV_TOOLTIPS_ELEMENT = "abbrev-tooltips";
const INT_LINK_ELEMENT = "int-link";
+const POPUP_IMAGE_ELEMENT = "popup-image";
class XSLTParseProcess {
#processors;
@@ -567,6 +568,88 @@ class ToolTip extends HTMLElement {
}
}
+class PopupImage extends HTMLElement {
+ constructor() {
+ super();
+ this.overlay = null;
+ this._preview = null;
+ this._description = null;
+ this._imageURL = "";
+ }
+
+ connectedCallback() {
+ this._imageURL = this.getAttribute("data-image-url") || "";
+ this._preview = this.querySelector("img");
+ this._description = this.querySelector(".image-description");
+
+ if (this._preview) {
+ this._preview.addEventListener("click", () => {
+ this.showOverlay();
+ });
+ }
+ }
+
+ disconnectedCallback() {
+ // Optionally remove the overlay if the element is removed from the DOM
+ if (this.overlay && this.overlay.parentNode) {
+ this.overlay.parentNode.removeChild(this.overlay);
+ }
+ }
+
+ showOverlay() {
+ const descriptionHtml = this._description ? this._description.innerHTML : "";
+ this.overlay = document.createElement("div");
+ this.overlay.classList.add(
+ "fixed",
+ "inset-0",
+ "z-50",
+ "bg-black/70",
+ "flex",
+ "items-center",
+ "justify-center",
+ "p-4",
+ );
+
+ this.overlay.innerHTML = `
+
+
+
+

+
+
+ ${descriptionHtml}
+
+
+ `;
+
+ const closeButton = this.overlay.querySelector("button");
+ if (closeButton) {
+ closeButton.addEventListener("click", () => {
+ this.hideOverlay();
+ });
+ }
+
+ this.overlay.addEventListener("click", (evt) => {
+ if (evt.target === this.overlay) {
+ this.hideOverlay();
+ }
+ });
+
+ document.body.appendChild(this.overlay);
+ }
+
+ hideOverlay() {
+ this.overlay.parentNode.removeChild(this.overlay);
+ this.overlay = null;
+ }
+}
+
class AbbreviationTooltips extends HTMLElement {
static get observedAttributes() {
return ["data-text", "data-abbrevmap"];
@@ -772,5 +855,6 @@ customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
customElements.define(FILTER_LIST_ELEMENT, FilterList);
customElements.define(SCROLL_BUTTON_ELEMENT, ScrollButton);
customElements.define(TOOLTIP_ELEMENT, ToolTip);
+customElements.define("popup-image", PopupImage);
export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips };
diff --git a/views/transform/site.css b/views/transform/site.css
index acfb547..219c1d7 100644
--- a/views/transform/site.css
+++ b/views/transform/site.css
@@ -406,4 +406,37 @@
#extendedsearchcolumn label {
@apply col-span-3 bg-stone-200 align-middle px-2.5 text-slate-900 items-center flex text-base;
}
+
+ .content .fields {
+ @apply grid grid-cols-10 gap-y-0.5 w-full gap-x-4;
+ }
+
+ .content .fieldlabel {
+ @apply col-span-1 font-bold whitespace-nowrap grow-0 shrink-0 font-sans text-sm align-baseline mt-1 text-right;
+ }
+
+ .content .fieldvalue {
+ @apply col-span-9 font-serif text-left grow align-top max-w-[60ch];
+ }
+
+ .content {
+ @apply text-base;
+ }
+
+ #almanachcontents .content {
+ @apply border-b-8 border-stone-50;
+ }
+
+ #almanachcontents .columnone {
+ @apply bg-stone-50 pt-2 pr-3 mr-1;
+ }
+
+ #almanachcontents .columntwo {
+ @apply bg-stone-100 py-4 pl-6 ml-1;
+ }
+
+ #almanachcontents .columnthree {
+ @apply bg-stone-100 pr-6 py-4;
+ /*direction: rtl;*/
+ }
}