exp akteure

This commit is contained in:
Simon Martens
2024-12-29 20:26:36 +01:00
parent 863b520d1c
commit e46d540c01
12 changed files with 151 additions and 121 deletions

View File

@@ -8,9 +8,8 @@ full_bin = "export KGPZ_WATCH=false; ./tmp/main"
cmd = "go build -tags=\"dev\" -o ./tmp/main ." cmd = "go build -tags=\"dev\" -o ./tmp/main ."
delay = 400 delay = 400
exclude_dir = [ exclude_dir = [
"views/public", "views/assets",
"views/node_modules", "views/node_modules",
"views/transform",
"tmp", "tmp",
"vendor", "vendor",
"testdata", "testdata",
@@ -23,7 +22,7 @@ exclude_regex = ["_test.go"]
exclude_unchanged = false exclude_unchanged = false
follow_symlink = false follow_symlink = false
include_dir = [] include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "gohtml"] include_ext = ["go", "tpl", "tmpl", "html", "gohtml", "js", "css", "xsl"]
include_file = [] include_file = []
kill_delay = "0s" kill_delay = "0s"
log = "build-errors.log" log = "build-errors.log"

View File

@@ -4,6 +4,8 @@ import (
"html/template" "html/template"
"io" "io"
"io/fs" "io/fs"
"path/filepath"
"strings"
"sync" "sync"
) )
@@ -14,6 +16,8 @@ var embed_cache sync.Map
func EmbedSafe(fs fs.FS) func(string) template.HTML { func EmbedSafe(fs fs.FS) func(string) template.HTML {
embed_cache.Clear() embed_cache.Clear()
return func(path string) template.HTML { return func(path string) template.HTML {
path = strings.TrimSpace(path)
path = filepath.Clean(path)
val, err := getFileData(fs, path) val, err := getFileData(fs, path)
if err != nil { if err != nil {
return template.HTML("") return template.HTML("")
@@ -26,6 +30,8 @@ func EmbedSafe(fs fs.FS) func(string) template.HTML {
func Embed(fs fs.FS) func(string) string { func Embed(fs fs.FS) func(string) string {
embed_cache.Clear() embed_cache.Clear()
return func(path string) string { return func(path string) string {
path = strings.TrimSpace(path)
path = filepath.Clean(path)
val, err := getFileData(fs, path) val, err := getFileData(fs, path)
if err != nil { if err != nil {
return "" return ""
@@ -54,3 +60,27 @@ func getFileData(fs fs.FS, path string) ([]byte, error) {
embed_cache.Store(path, data) embed_cache.Store(path, data)
return data, nil return data, nil
} }
func EmbedXSLT(fs fs.FS) func(string) template.HTML {
embed_cache.Clear()
return func(path string) template.HTML {
path = strings.TrimSpace(path)
path = filepath.Clean(path)
fn := filepath.Base(path)
ext := filepath.Ext(fn)
fn = fn[:len(fn)-len(ext)]
if (ext != ".xsl" && ext != ".xslt") || ext == "" || fn == "" {
return template.HTML("[ERROR: " + "file is not an XSLT file" + "]")
}
val, err := getFileData(fs, path)
if err != nil {
return template.HTML("[ERROR: " + err.Error() + "]")
}
src := "<script id=\"" + fn + "\" type=\"application/xml\">\n" + string(val) + "\n</script>"
return template.HTML(src)
}
}

View File

@@ -55,6 +55,9 @@ func (e *Engine) Funcs(app *app.KGPZ) error {
e.AddFunc("EmbedSafe", functions.EmbedSafe(views.StaticFS)) e.AddFunc("EmbedSafe", functions.EmbedSafe(views.StaticFS))
e.AddFunc("Embed", functions.Embed(views.StaticFS)) e.AddFunc("Embed", functions.Embed(views.StaticFS))
// Embedding of XSLT files
e.AddFunc("EmbedXSLT", functions.EmbedXSLT(views.StaticFS))
// App specific // App specific
e.AddFunc("GetAgent", app.Library.Agents.Item) e.AddFunc("GetAgent", app.Library.Agents.Item)
e.AddFunc("GetPlace", app.Library.Places.Item) e.AddFunc("GetPlace", app.Library.Places.Item)

View File

@@ -1,54 +1,51 @@
const u = "[xslt-onload]", a = "xslt-template", c = "xslt-transformed", i = /* @__PURE__ */ new Map(); const p = "script[xslt-onload]", a = "xslt-template", u = "xslt-transformed", c = /* @__PURE__ */ new Map();
function p() { function m() {
let t = htmx.findAll(u); let t = htmx.findAll(p);
for (let e of t) for (let e of t)
f(e); T(e);
} }
function f(t) { function T(t) {
if (t.getAttribute(c) === "true" || !t.hasAttribute(a)) if (t.getAttribute(u) === "true" || !t.hasAttribute(a))
return; return;
let e = "#" + t.getAttribute(a), r = i.get(e); let e = "#" + t.getAttribute(a), o = c.get(e);
if (!r) { if (!o) {
let o = htmx.find(e); let n = htmx.find(e);
if (o) { if (n) {
let n = o.innerHTML ? new DOMParser().parseFromString(o.innerHTML, "application/xml") : o.contentDocument; let l = n.innerHTML ? new DOMParser().parseFromString(n.innerHTML, "application/xml") : n.contentDocument;
r = new XSLTProcessor(), r.importStylesheet(n), i.set(e, r); o = new XSLTProcessor(), o.importStylesheet(l), c.set(e, o);
} else } else
throw new Error("Unknown XSLT template: " + e); throw new Error("Unknown XSLT template: " + e);
} }
if (r) { let i = new DOMParser().parseFromString(t.innerHTML, "application/xml"), s = o.transformToFragment(i, document), r = new XMLSerializer().serializeToString(s);
let o = new DOMParser().parseFromString(t.innerHTML, "application/xml"), n = r.transformToFragment(o, document), s = new XMLSerializer().serializeToString(n); t.outerHTML = r;
t.innerHTML = s, t.setAttribute(c, !0), htmx.process(t);
} else
throw new Error("No Processor: " + e);
} }
function T() { function f() {
document.querySelectorAll("template[simple]").forEach((e) => { document.querySelectorAll("template[simple]").forEach((e) => {
let r = e.getAttribute("id"), o = e.content; let o = e.getAttribute("id"), i = e.content;
customElements.define( customElements.define(
r, o,
class extends HTMLElement { class extends HTMLElement {
constructor() { constructor() {
super(), this.appendChild(o.cloneNode(!0)), this.slots = this.querySelectorAll("slot"); super(), this.appendChild(i.cloneNode(!0)), this.slots = this.querySelectorAll("slot");
} }
connectedCallback() { connectedCallback() {
let n = []; let s = [];
this.slots.forEach((s) => { this.slots.forEach((r) => {
let m = s.getAttribute("name"), l = this.querySelector(`[slot="${m}"]`); let n = r.getAttribute("name"), l = this.querySelector(`[slot="${n}"]`);
l && (s.replaceWith(l.cloneNode(!0)), n.push(l)); l && (r.replaceWith(l.cloneNode(!0)), s.push(l));
}), n.forEach((s) => { }), s.forEach((r) => {
s.remove(); r.remove();
}); });
} }
} }
); );
}); });
} }
function h() { function d() {
p(), htmx.on("htmx:afterSettle", function(t) { m(), htmx.on("htmx:load", function(t) {
i.clear(), p(); m();
}), T(); }), f();
} }
export { export {
h as setup d as setup
}; };

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,5 @@
{{ if ne (len .model.Search) 1 }} {{ if ne (len .model.Search) 1 }}
{{ $agent := index $.model.Agents .model.Search }} {{ $agent := index $.model.Agents .model.Search }}
{{ if not $agent }} {{ if not $agent }}
<div>Agent nicht gefunden: {{ .model.Search }}</div> <div>Agent nicht gefunden: {{ .model.Search }}</div>
@@ -10,8 +11,9 @@
{{ $letter }} {{ $letter }}
</a> </a>
</div> </div>
<div>{{ index $agent.Names 0 }}</div> <div>{{ template "_agent" $agent }}</div>
{{ end }} {{ end }}
{{ else }} {{ else }}
<div> <div>
{{ range $_, $l := .model.AvailableLetters }} {{ range $_, $l := .model.AvailableLetters }}
@@ -23,75 +25,8 @@
{{ range $_, $id := .model.Sorted }} {{ range $_, $id := .model.Sorted }}
{{ $a := index $.model.Agents $id }} {{ $a := index $.model.Agents $id }}
{{ if and $a (ne (len $a.Names) 0) }} {{ template "_agent" $a }}
<div class="pb-4">
{{ index $a.Names 0 }}
<div>
{{ $gnd := GetGND $a.GND }}
{{ if (ne $gnd nil) }}
{{- if ne (len $gnd.DateOfBirth) 0 -}}
<i class="ri-asterisk text-xs relative bottom-0.5"></i>&nbsp;
{{- HRDateShort (index $gnd.DateOfBirth 0) -}}
{{- end -}}
{{- if ne (len $gnd.DateOfDeath) 0 }}
&emsp;<i class="ri-cross-fill text-xs relative bottom-0.5"></i
>&nbsp;{{ HRDateShort (index $gnd.DateOfDeath 0) }}
{{ end }}
{{- if ne (len $gnd.ProfessionOrOccupation) 0 -}}
<div>
{{- (index $gnd.ProfessionOrOccupation 0).Label -}}
{{- if gt (len $gnd.ProfessionOrOccupation) 1 -}}
,
{{ (index $gnd.ProfessionOrOccupation 1).Label -}}
{{ end -}}
{{- if gt (len $gnd.ProfessionOrOccupation) 2 -}}
,
{{ (index $gnd.ProfessionOrOccupation 2).Label -}}
{{ end -}}
</div>
{{ end }}
{{ end }}
<div class="flex gap-x-2 flex-row">
<a href="/akteure/{{ $id }}" class="!no-underline"><i class="ri-links-line"></i></a>
{{- if ne $gnd nil -}}
<a href="{{ $a.GND }}" target="_blank">GND &rarr;</a>
{{- if ne (len $gnd.Wikipedia) 0 -}}
<a href="{{ (index $gnd.Wikipedia 0).Label }}" target="_blank">WIKI &rarr;</a>
{{ end -}}
{{ end }}
</div>
</div>
{{- if ne (len $a.Works) 0 -}}
<div>
{{ range $_, $w := $a.Works }}
{{- if ne (len $w.Citation.InnerXML ) 0 -}}
<div xslt-template="citation-xslt" xslt-onload>
<xml>
{{- Safe $w.Citation.InnerXML -}}
</xml>
</div>
{{- end -}}
{{ end }}
</div>
{{ end }}
{{- if ne (len $a.Pieces) 0 -}}
<div>
{{ range $_, $p := $a.Pieces }}
{{- range $_, $i := $p.IssueRefs -}}
<div>
<a href="/{{ $i.When }}/{{ $i.Nr }}">{{ $i.Nr }}/{{ $i.When }}</a>
</div>
{{- end -}}
{{ end }}
</div>
{{ end }}
</div>
{{ end }}
{{ end }} {{ end }}
{{ end }} {{ end }}
<script id="citation-xslt" type="application/xml"> {{ EmbedXSLT "xslt/transform-citation.xsl" }}
{{ EmbedSafe "xslt/citation.xsl" }}
</script>

View File

@@ -0,0 +1,72 @@
{{ $a := . }}
{{ if and $a (ne (len $a.Names) 0) }}
<div class="pb-4">
{{ index $a.Names 0 }}
<div>
{{ $gnd := GetGND $a.GND }}
{{ if (ne $gnd nil) }}
{{- if ne (len $gnd.DateOfBirth) 0 -}}
<i class="ri-asterisk text-xs relative bottom-0.5"></i>&nbsp;
{{- HRDateShort (index $gnd.DateOfBirth 0) -}}
{{- end -}}
{{- if ne (len $gnd.DateOfDeath) 0 }}
&emsp;<i class="ri-cross-fill text-xs relative bottom-0.5"></i
>&nbsp;{{ HRDateShort (index $gnd.DateOfDeath 0) }}
{{ end }}
{{- if ne (len $gnd.ProfessionOrOccupation) 0 -}}
<div>
{{- (index $gnd.ProfessionOrOccupation 0).Label -}}
{{- if gt (len $gnd.ProfessionOrOccupation) 1 -}}
,
{{ (index $gnd.ProfessionOrOccupation 1).Label -}}
{{ end -}}
{{- if gt (len $gnd.ProfessionOrOccupation) 2 -}}
,
{{ (index $gnd.ProfessionOrOccupation 2).Label -}}
{{ end -}}
</div>
{{ end }}
{{ end }}
<div class="flex gap-x-2 flex-row">
<a href="/akteure/{{ $a.ID }}" class="!no-underline"><i class="ri-links-line"></i></a>
{{- if ne $gnd nil -}}
<a href="{{ $a.GND }}" target="_blank">GND &rarr;</a>
{{- if ne (len $gnd.Wikipedia) 0 -}}
<a href="{{ (index $gnd.Wikipedia 0).Label }}" target="_blank">WIKI &rarr;</a>
{{ end -}}
{{ end }}
</div>
</div>
{{- if ne (len $a.Works) 0 -}}
<div>
{{ range $_, $w := $a.Works }}
{{- if ne (len $w.Citation.InnerXML ) 0 -}}
<script type="application/xml" xslt-template="transform-citation" xslt-onload>
<xml>
{{- Safe $w.Citation.InnerXML -}}
</xml>
</script>
{{- end -}}
{{ end }}
</div>
{{ end }}
{{- if ne (len $a.Pieces) 0 -}}
<div>
{{ range $_, $p := $a.Pieces }}
{{- range $_, $i := $p.IssueRefs -}}
<div>
<a href="/{{ $i.When }}/{{ $i.Nr }}">{{ $i.Nr }}/{{ $i.When }}</a>
</div>
{{- end -}}
{{ end }}
</div>
{{ end }}
</div>
{{ end }}

View File

@@ -4,6 +4,7 @@ export default {
"./routes/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}", "./routes/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}",
"./layouts/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}", "./layouts/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}",
"./transform/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}", "./transform/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml}",
"./public/**/*.{html,js,svelte,ts,tmpl,gotmpl,gohtml,xsl}",
], ],
theme: { theme: {
extend: { extend: {

View File

@@ -1,6 +1,6 @@
import "./site.css"; import "./site.css";
const ATTR_XSLT_ONLOAD = "[xslt-onload]"; const ATTR_XSLT_ONLOAD = "script[xslt-onload]";
const ATTR_XSLT_TEMPLATE = "xslt-template"; const ATTR_XSLT_TEMPLATE = "xslt-template";
const ATTR_XSLT_STATE = "xslt-transformed"; const ATTR_XSLT_STATE = "xslt-transformed";
@@ -37,18 +37,10 @@ function transform_xslt(element) {
} }
} }
if (processor) { let data = new DOMParser().parseFromString(element.innerHTML, "application/xml");
let data = new DOMParser().parseFromString(element.innerHTML, "application/xml"); let frag = processor.transformToFragment(data, document);
let frag = processor.transformToFragment(data, document); let s = new XMLSerializer().serializeToString(frag);
let s = new XMLSerializer().serializeToString(frag); element.outerHTML = s;
element.innerHTML = s;
element.setAttribute(ATTR_XSLT_STATE, true);
// INFO: This allows to insert htmx elements in the transformed content
htmx.process(element);
} else {
throw new Error("No Processor: " + templateId);
}
} }
function setup_templates() { function setup_templates() {
@@ -89,8 +81,9 @@ function setup_templates() {
function setup() { function setup() {
setup_xslt(); setup_xslt();
htmx.on("htmx:afterSettle", function (_) { htmx.on("htmx:load", function (_) {
xslt_processors.clear(); // INFO: We can instead use afterSettle; and also clear the map with
// xslt_processors.clear();
setup_xslt(); setup_xslt();
}); });