mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 09:15:33 +00:00
Statische Seiten
This commit is contained in:
67
helpers/functions/datetime.go
Normal file
67
helpers/functions/datetime.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package functions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Weekday struct {
|
||||||
|
Name string
|
||||||
|
ShortName string
|
||||||
|
Number int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Month struct {
|
||||||
|
Name string
|
||||||
|
ShortName string
|
||||||
|
Number int
|
||||||
|
}
|
||||||
|
|
||||||
|
var Months = []Month{
|
||||||
|
{"Januar", "Jan", 1},
|
||||||
|
{"Februar", "Feb", 2},
|
||||||
|
{"März", "Mär", 3},
|
||||||
|
{"April", "Apr", 4},
|
||||||
|
{"Mai", "Mai", 5},
|
||||||
|
{"Juni", "Jun", 6},
|
||||||
|
{"Juli", "Jul", 7},
|
||||||
|
{"August", "Aug", 8},
|
||||||
|
{"September", "Sep", 9},
|
||||||
|
{"Oktober", "Okt", 10},
|
||||||
|
{"November", "Nov", 11},
|
||||||
|
{"Dezember", "Dez", 12},
|
||||||
|
{"N/A", "N/A", 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
var Weekdays = []Weekday{
|
||||||
|
{"Sonntag", "So", 0},
|
||||||
|
{"Montag", "Mo", 1},
|
||||||
|
{"Dienstag", "Di", 2},
|
||||||
|
{"Mittwoch", "Mi", 3},
|
||||||
|
{"Donnerstag", "Do", 4},
|
||||||
|
{"Freitag", "Fr", 5},
|
||||||
|
{"Samstag", "Sa", 6},
|
||||||
|
{"N/A", "N/A", 7},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Today() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMonth(month any) Month {
|
||||||
|
if val, ok := month.(int); ok {
|
||||||
|
val -= 1
|
||||||
|
if val < 0 || val > 11 {
|
||||||
|
val = 12
|
||||||
|
}
|
||||||
|
return Months[val]
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := month.(time.Time); ok {
|
||||||
|
m := val.Month() - 1
|
||||||
|
return Months[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Invalid month value", month)
|
||||||
|
return Months[12]
|
||||||
|
}
|
||||||
11
helpers/functions/int.go
Normal file
11
helpers/functions/int.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package functions
|
||||||
|
|
||||||
|
func Add(a, b any) int {
|
||||||
|
val1, ok1 := a.(int)
|
||||||
|
val2, ok2 := b.(int)
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return val1 + val2
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ func Arr(els ...any) []any {
|
|||||||
return els
|
return els
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must have even number of args: key, value, key, value, ...
|
||||||
func Dict(values ...interface{}) (map[string]interface{}, error) {
|
func Dict(values ...interface{}) (map[string]interface{}, error) {
|
||||||
// Must have even number of args: key, value, key, value, ...
|
|
||||||
if len(values)%2 != 0 {
|
if len(values)%2 != 0 {
|
||||||
return nil, fmt.Errorf("invalid dict call: must have even number of args")
|
return nil, fmt.Errorf("invalid dict call: must have even number of args")
|
||||||
}
|
}
|
||||||
|
|||||||
48
helpers/functions/toc.go
Normal file
48
helpers/functions/toc.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package functions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TOCEntry struct {
|
||||||
|
Level int
|
||||||
|
Title string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getText(n *html.Node) string {
|
||||||
|
if n.Type == html.TextNode {
|
||||||
|
return n.Data
|
||||||
|
}
|
||||||
|
var sb strings.Builder
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
sb.WriteString(getText(c))
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TOCFromHTML(htmlStr string) ([]TOCEntry, error) {
|
||||||
|
doc, err := html.Parse(strings.NewReader(htmlStr))
|
||||||
|
toc := []TOCEntry{}
|
||||||
|
if err != nil {
|
||||||
|
return toc, err
|
||||||
|
}
|
||||||
|
var f func(*html.Node)
|
||||||
|
f = func(n *html.Node) {
|
||||||
|
if n.Type == html.ElementNode {
|
||||||
|
if len(n.Data) == 2 && n.Data[0] == 'h' && n.Data[1] >= '1' && n.Data[1] <= '6' {
|
||||||
|
level, err := strconv.Atoi(n.Data[1:])
|
||||||
|
if err == nil {
|
||||||
|
title := strings.TrimSpace(getText(n))
|
||||||
|
toc = append(toc, TOCEntry{Level: level, Title: title})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
f(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(doc)
|
||||||
|
return toc, nil
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ func init() {
|
|||||||
RegisterTextPage("/edition/danksagungen/", pagemodels.P_DANK_NAME)
|
RegisterTextPage("/edition/danksagungen/", pagemodels.P_DANK_NAME)
|
||||||
RegisterTextPage("/edition/literatur/", pagemodels.P_LIT_NAME)
|
RegisterTextPage("/edition/literatur/", pagemodels.P_LIT_NAME)
|
||||||
RegisterTextPage("/edition/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME)
|
RegisterTextPage("/edition/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME)
|
||||||
|
RegisterTextPage("/edition/dokumentation/", pagemodels.P_DOK_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterStaticPage(url, name string) {
|
func RegisterStaticPage(url, name string) {
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ Modelle umwandeln (zzt RecordProxy)
|
|||||||
- Technologie-Stack auf Server-Rendering / Go Templates umgestellt
|
- Technologie-Stack auf Server-Rendering / Go Templates umgestellt
|
||||||
- Die Seiten sollten jetzt insgesamt schneller laden
|
- Die Seiten sollten jetzt insgesamt schneller laden
|
||||||
|
|
||||||
- Man kann auf der Startseite nach Almanach-Nummern suchen
|
- Man kann auf der Startseite und in der Suche nach Almanach-Nummern suchen
|
||||||
- Überall werden die Almanachnummer und Inhaltsnummer angezeigt
|
- Überall werden die Almanachnummer und Inhaltsnummer angezeigt
|
||||||
- Die URL referenziert die Almanachnummern, nicht mher die DB-IDs
|
- Die URL referenziert die Almanachnummern, nicht mher die Datenbank-IDs
|
||||||
|
|
||||||
- In der Almanach-Ansicht werden die Abkürzungen erklärt
|
- In der Almanach-Ansicht werden die Abkürzungen erklärt
|
||||||
- In der Almanach- und Suchansicht werden Sammlungen abgehoben
|
- In der Almanach- und Suchansicht werden Sammlungen abgehoben
|
||||||
|
|||||||
@@ -47,11 +47,25 @@ func NewEngine(layouts, templates *fs.FS) *Engine {
|
|||||||
func (e *Engine) funcs() error {
|
func (e *Engine) funcs() error {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
e.mu.Unlock()
|
e.mu.Unlock()
|
||||||
|
|
||||||
|
// Passing HTML
|
||||||
e.AddFunc("Safe", functions.Safe)
|
e.AddFunc("Safe", functions.Safe)
|
||||||
|
// Creating an array or dict (to pass to a template)
|
||||||
e.AddFunc("Arr", functions.Arr)
|
e.AddFunc("Arr", functions.Arr)
|
||||||
e.AddFunc("HasPrefix", strings.HasPrefix)
|
|
||||||
e.AddFunc("Dict", functions.Dict)
|
e.AddFunc("Dict", functions.Dict)
|
||||||
|
|
||||||
|
// Datatype Functions
|
||||||
|
e.AddFunc("HasPrefix", strings.HasPrefix)
|
||||||
e.AddFunc("Contains", functions.Contains)
|
e.AddFunc("Contains", functions.Contains)
|
||||||
|
e.AddFunc("Add", functions.Add)
|
||||||
|
|
||||||
|
// Time & Date Functions
|
||||||
|
e.AddFunc("Today", functions.Today)
|
||||||
|
e.AddFunc("GetMonth", functions.GetMonth)
|
||||||
|
|
||||||
|
// TOC
|
||||||
|
e.AddFunc("TOCFromHTML", functions.TOCFromHTML)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
var L = (s) => {
|
var _ = (s) => {
|
||||||
throw TypeError(s);
|
throw TypeError(s);
|
||||||
};
|
};
|
||||||
var T = (s, e, t) => e.has(s) || L("Cannot " + t);
|
var T = (s, e, t) => e.has(s) || _("Cannot " + t);
|
||||||
var g = (s, e, t) => (T(s, e, "read from private field"), t ? t.call(s) : e.get(s)), c = (s, e, t) => e.has(s) ? L("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(s) : e.set(s, t), u = (s, e, t, i) => (T(s, e, "write to private field"), i ? i.call(s, t) : e.set(s, t), t), f = (s, e, t) => (T(s, e, "access private method"), t);
|
var f = (s, e, t) => (T(s, e, "read from private field"), t ? t.call(s) : e.get(s)), c = (s, e, t) => e.has(s) ? _("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(s) : e.set(s, t), d = (s, e, t, i) => (T(s, e, "write to private field"), i ? i.call(s, t) : e.set(s, t), t), g = (s, e, t) => (T(s, e, "access private method"), t);
|
||||||
const w = "script[xslt-onload]", v = "xslt-template", A = "xslt-transformed", k = "filter-list", m = "filter-list-list", M = "filter-list-item", y = "filter-list-input", x = "filter-list-searchable", B = "scroll-button", P = "tool-tip", I = "abbrev-tooltips";
|
const k = "script[xslt-onload]", v = "xslt-template", w = "xslt-transformed", A = "filter-list", m = "filter-list-list", M = "filter-list-item", y = "filter-list-input", x = "filter-list-searchable", B = "scroll-button", I = "tool-tip", P = "abbrev-tooltips", C = "int-link";
|
||||||
var h, b, E;
|
var h, b, E;
|
||||||
class R {
|
class z {
|
||||||
constructor() {
|
constructor() {
|
||||||
c(this, b);
|
c(this, b);
|
||||||
c(this, h);
|
c(this, h);
|
||||||
u(this, h, /* @__PURE__ */ new Map());
|
d(this, h, /* @__PURE__ */ new Map());
|
||||||
}
|
}
|
||||||
setup() {
|
setup() {
|
||||||
let e = htmx.findAll(w);
|
let e = htmx.findAll(k);
|
||||||
for (let t of e)
|
for (let t of e)
|
||||||
f(this, b, E).call(this, t);
|
g(this, b, E).call(this, t);
|
||||||
}
|
}
|
||||||
hookupHTMX() {
|
hookupHTMX() {
|
||||||
htmx.on("htmx:load", (e) => {
|
htmx.on("htmx:load", (e) => {
|
||||||
@@ -23,26 +23,26 @@ class R {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
h = new WeakMap(), b = new WeakSet(), E = function(e) {
|
h = new WeakMap(), b = new WeakSet(), E = function(e) {
|
||||||
if (e.getAttribute(A) === "true" || !e.hasAttribute(v))
|
if (e.getAttribute(w) === "true" || !e.hasAttribute(v))
|
||||||
return;
|
return;
|
||||||
let t = "#" + e.getAttribute(v), i = g(this, h).get(t);
|
let t = "#" + e.getAttribute(v), i = f(this, h).get(t);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
let l = htmx.find(t);
|
let l = htmx.find(t);
|
||||||
if (l) {
|
if (l) {
|
||||||
let S = l.innerHTML ? new DOMParser().parseFromString(l.innerHTML, "application/xml") : l.contentDocument;
|
let S = l.innerHTML ? new DOMParser().parseFromString(l.innerHTML, "application/xml") : l.contentDocument;
|
||||||
i = new XSLTProcessor(), i.importStylesheet(S), g(this, h).set(t, i);
|
i = new XSLTProcessor(), i.importStylesheet(S), f(this, h).set(t, i);
|
||||||
} else
|
} else
|
||||||
throw new Error("Unknown XSLT template: " + t);
|
throw new Error("Unknown XSLT template: " + t);
|
||||||
}
|
}
|
||||||
let r = new DOMParser().parseFromString(e.innerHTML, "application/xml"), n = i.transformToFragment(r, document), a = new XMLSerializer().serializeToString(n);
|
let r = new DOMParser().parseFromString(e.innerHTML, "application/xml"), n = i.transformToFragment(r, document), o = new XMLSerializer().serializeToString(n);
|
||||||
e.outerHTML = a;
|
e.outerHTML = o;
|
||||||
};
|
};
|
||||||
var o, p, _;
|
var a, p, L;
|
||||||
class H extends HTMLElement {
|
class H extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
c(this, p);
|
c(this, p);
|
||||||
c(this, o, !1);
|
c(this, a, !1);
|
||||||
this._items = [], this._url = "", this._filterstart = !1, this._placeholder = "Liste filtern...", this.render();
|
this._items = [], this._url = "", this._filterstart = !1, this._placeholder = "Liste filtern...", this.render();
|
||||||
}
|
}
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
@@ -55,7 +55,7 @@ class H extends HTMLElement {
|
|||||||
return this._items;
|
return this._items;
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this._url = this.getAttribute("data-url") || "./", this._filterstart = this.getAttribute("data-filterstart") === "true", this._placeholder = this.getAttribute("data-placeholder") || "Liste filtern...", this._filterstart && u(this, o, !0), this.addEventListener("input", this.onInput.bind(this)), this.addEventListener("keydown", this.onEnter.bind(this)), this.addEventListener("focusin", this.onGainFocus.bind(this)), this.addEventListener("focusout", this.onLoseFocus.bind(this));
|
this._url = this.getAttribute("data-url") || "./", this._filterstart = this.getAttribute("data-filterstart") === "true", this._placeholder = this.getAttribute("data-placeholder") || "Liste filtern...", this._filterstart && d(this, a, !0), this.addEventListener("input", this.onInput.bind(this)), this.addEventListener("keydown", this.onEnter.bind(this)), this.addEventListener("focusin", this.onGainFocus.bind(this)), this.addEventListener("focusout", this.onLoseFocus.bind(this));
|
||||||
}
|
}
|
||||||
attributeChangedCallback(t, i, r) {
|
attributeChangedCallback(t, i, r) {
|
||||||
t === "data-url" && i !== r && (this._url = r, this.render()), t === "data-filterstart" && i !== r && (this._filterstart = r === "true", this.render()), t === "data-placeholder" && i !== r && (this._placeholder = r, this.render());
|
t === "data-url" && i !== r && (this._url = r, this.render()), t === "data-filterstart" && i !== r && (this._filterstart = r === "true", this.render()), t === "data-placeholder" && i !== r && (this._placeholder = r, this.render());
|
||||||
@@ -64,14 +64,14 @@ class H extends HTMLElement {
|
|||||||
t.target && t.target.tagName.toLowerCase() === "input" && (this._filter = t.target.value, this.renderList());
|
t.target && t.target.tagName.toLowerCase() === "input" && (this._filter = t.target.value, this.renderList());
|
||||||
}
|
}
|
||||||
onGainFocus(t) {
|
onGainFocus(t) {
|
||||||
t.target && t.target.tagName.toLowerCase() === "input" && (u(this, o, !1), this.renderList());
|
t.target && t.target.tagName.toLowerCase() === "input" && (d(this, a, !1), this.renderList());
|
||||||
}
|
}
|
||||||
onLoseFocus(t) {
|
onLoseFocus(t) {
|
||||||
let i = this.querySelector("input");
|
let i = this.querySelector("input");
|
||||||
if (t.target && t.target === i) {
|
if (t.target && t.target === i) {
|
||||||
if (relatedElement = t.relatedTarget, relatedElement && this.contains(relatedElement))
|
if (relatedElement = t.relatedTarget, relatedElement && this.contains(relatedElement))
|
||||||
return;
|
return;
|
||||||
i.value = "", this._filter = "", this._filterstart && u(this, o, !0), this.renderList();
|
i.value = "", this._filter = "", this._filterstart && d(this, a, !0), this.renderList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEnter(t) {
|
onEnter(t) {
|
||||||
@@ -139,7 +139,7 @@ class H extends HTMLElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
ActiveDot(t) {
|
ActiveDot(t) {
|
||||||
return f(this, p, _).call(this, t), "";
|
return g(this, p, L).call(this, t), "";
|
||||||
}
|
}
|
||||||
NoItems(t) {
|
NoItems(t) {
|
||||||
return t.length === 0 ? '<div class="px-2 py-0.5 italic text-gray-500">Keine Einträge gefunden</div>' : "";
|
return t.length === 0 ? '<div class="px-2 py-0.5 italic text-gray-500">Keine Einträge gefunden</div>' : "";
|
||||||
@@ -167,13 +167,13 @@ class H extends HTMLElement {
|
|||||||
t = this._items.filter((r) => i.every((n) => this.getSearchText(r).toLowerCase().includes(n.toLowerCase())));
|
t = this._items.filter((r) => i.every((n) => this.getSearchText(r).toLowerCase().includes(n.toLowerCase())));
|
||||||
}
|
}
|
||||||
return `
|
return `
|
||||||
<div id="${m}" class="${m} pt-1 min-h-[19rem] max-h-60 overflow-auto border-b border-zinc-300 bg-stone-50 ${g(this, o) ? "hidden" : ""}">
|
<div id="${m}" class="${m} pt-1 min-h-[19rem] max-h-60 overflow-auto border-b border-zinc-300 bg-stone-50 ${f(this, a) ? "hidden" : ""}">
|
||||||
${t.map(
|
${t.map(
|
||||||
(i, r) => `
|
(i, r) => `
|
||||||
<a
|
<a
|
||||||
href="${this._url}${this.getHREF(i)}"
|
href="${this._url}${this.getHREF(i)}"
|
||||||
class="${M} block px-2.5 py-0.5 hover:bg-slate-200 no-underline ${r % 2 === 0 ? "bg-stone-100" : "bg-stone-50"}"
|
class="${M} block px-2.5 py-0.5 hover:bg-slate-200 no-underline ${r % 2 === 0 ? "bg-stone-100" : "bg-stone-50"}"
|
||||||
${f(this, p, _).call(this, i) ? 'aria-current="page"' : ""}>
|
${g(this, p, L).call(this, i) ? 'aria-current="page"' : ""}>
|
||||||
${this.ActiveDot(i)}
|
${this.ActiveDot(i)}
|
||||||
${this.getLinkText(i)}
|
${this.getLinkText(i)}
|
||||||
</a>
|
</a>
|
||||||
@@ -184,13 +184,13 @@ class H extends HTMLElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o = new WeakMap(), p = new WeakSet(), _ = function(t) {
|
a = new WeakMap(), p = new WeakSet(), L = function(t) {
|
||||||
if (!t)
|
if (!t)
|
||||||
return !1;
|
return !1;
|
||||||
let i = this.getHREF(t);
|
let i = this.getHREF(t);
|
||||||
return !(i === "" || !window.location.href.endsWith(i));
|
return !(i === "" || !window.location.href.endsWith(i));
|
||||||
};
|
};
|
||||||
class C extends HTMLElement {
|
class $ extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.handleScroll = this.handleScroll.bind(this), this.scrollToTop = this.scrollToTop.bind(this);
|
super(), this.handleScroll = this.handleScroll.bind(this), this.scrollToTop = this.scrollToTop.bind(this);
|
||||||
}
|
}
|
||||||
@@ -334,7 +334,7 @@ class F extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class d extends HTMLElement {
|
class u extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ["data-text", "data-abbrevmap"];
|
return ["data-text", "data-abbrevmap"];
|
||||||
}
|
}
|
||||||
@@ -397,7 +397,7 @@ class d extends HTMLElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this._abbrevMap = d.defaultAbbrevMap;
|
super(), this._abbrevMap = u.defaultAbbrevMap;
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.render();
|
this.render();
|
||||||
@@ -407,13 +407,13 @@ class d extends HTMLElement {
|
|||||||
}
|
}
|
||||||
_parseAndSetAbbrevMap(e) {
|
_parseAndSetAbbrevMap(e) {
|
||||||
if (!e) {
|
if (!e) {
|
||||||
this._abbrevMap = d.defaultAbbrevMap;
|
this._abbrevMap = u.defaultAbbrevMap;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this._abbrevMap = JSON.parse(e);
|
this._abbrevMap = JSON.parse(e);
|
||||||
} catch {
|
} catch {
|
||||||
this._abbrevMap = d.defaultAbbrevMap;
|
this._abbrevMap = u.defaultAbbrevMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setAbbrevMap(e) {
|
setAbbrevMap(e) {
|
||||||
@@ -437,17 +437,17 @@ class d extends HTMLElement {
|
|||||||
}
|
}
|
||||||
const n = this.findLongestAbbrevAt(e, r, t);
|
const n = this.findLongestAbbrevAt(e, r, t);
|
||||||
if (n) {
|
if (n) {
|
||||||
const { match: a, meaning: l } = n;
|
const { match: o, meaning: l } = n;
|
||||||
i += `
|
i += `
|
||||||
<tool-tip position="top" class="!inline" timeout="300">
|
<tool-tip position="top" class="!inline" timeout="300">
|
||||||
<div class="data-tip p-2 text-sm text-white bg-gray-700 rounded shadow">
|
<div class="data-tip p-2 text-sm text-white bg-gray-700 rounded shadow">
|
||||||
${l}
|
${l}
|
||||||
</div>
|
</div>
|
||||||
<span class="cursor-help text-blue-900 hover:text-slate-800">
|
<span class="cursor-help text-blue-900 hover:text-slate-800">
|
||||||
${a}
|
${o}
|
||||||
</span>
|
</span>
|
||||||
</tool-tip>
|
</tool-tip>
|
||||||
`, r += a.length;
|
`, r += o.length;
|
||||||
} else
|
} else
|
||||||
i += e[r], r++;
|
i += e[r], r++;
|
||||||
}
|
}
|
||||||
@@ -455,21 +455,40 @@ class d extends HTMLElement {
|
|||||||
}
|
}
|
||||||
findLongestAbbrevAt(e, t, i) {
|
findLongestAbbrevAt(e, t, i) {
|
||||||
let r = null, n = 0;
|
let r = null, n = 0;
|
||||||
for (const a of Object.keys(i))
|
for (const o of Object.keys(i))
|
||||||
e.startsWith(a, t) && a.length > n && (r = a, n = a.length);
|
e.startsWith(o, t) && o.length > n && (r = o, n = o.length);
|
||||||
return r ? { match: r, meaning: i[r] } : null;
|
return r ? { match: r, meaning: i[r] } : null;
|
||||||
}
|
}
|
||||||
isSpaceOrPunct(e) {
|
isSpaceOrPunct(e) {
|
||||||
return /\s|[.,;:!?]/.test(e);
|
return /\s|[.,;:!?]/.test(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define(I, d);
|
class N extends HTMLElement {
|
||||||
customElements.define(k, H);
|
constructor() {
|
||||||
customElements.define(B, C);
|
super();
|
||||||
customElements.define(P, F);
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.style.cursor = "pointer", this.addEventListener("click", this.handleClick);
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
this.removeEventListener("click", this.handleClick);
|
||||||
|
}
|
||||||
|
handleClick(e) {
|
||||||
|
const t = this.getAttribute("data-jump");
|
||||||
|
if (t) {
|
||||||
|
const i = document.querySelector(t);
|
||||||
|
i ? i.scrollIntoView({ behavior: "smooth" }) : console.warn(`No element found for selector: ${t}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define(C, N);
|
||||||
|
customElements.define(P, u);
|
||||||
|
customElements.define(A, H);
|
||||||
|
customElements.define(B, $);
|
||||||
|
customElements.define(I, F);
|
||||||
export {
|
export {
|
||||||
d as AbbreviationTooltips,
|
u as AbbreviationTooltips,
|
||||||
H as FilterList,
|
H as FilterList,
|
||||||
C as ScrollButton,
|
$ as ScrollButton,
|
||||||
R as XSLTParseProcess
|
z as XSLTParseProcess
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1 +1,22 @@
|
|||||||
<div class="mt-12 pt-3 border-t">Datenschutz, Impressum.</div>
|
{{- $date := Today -}}
|
||||||
|
<footer class="container-normal pb-1.5 text-base text-gray-800">
|
||||||
|
<div class="mt-12 pt-3 flex flex-row justify-between">
|
||||||
|
<div>
|
||||||
|
<i class="ri-creative-commons-line"></i>
|
||||||
|
<i class="ri-creative-commons-by-line"></i>
|
||||||
|
<a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>
|
||||||
|
<span>·</span>
|
||||||
|
<span>{{- (GetMonth $date).Name }} {{ $date.Year }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span>{{- .site.title }} – ein Projekt der</span>
|
||||||
|
<a href="https://theodor-springmann-stiftung.de">Theodor Springmann Stiftung</a>
|
||||||
|
<span>·</span>
|
||||||
|
<a href="/datenschutz/">Impressum & Datenschutz</a>
|
||||||
|
<span>·</span>
|
||||||
|
<i class="ri-code-line"></i>
|
||||||
|
<a href="https://github.com/Theodor-Springmann-Stiftung/musenalm">Code</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<button
|
<button
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/edition") -}}
|
||||||
aria-current="true"
|
aria-current="true"
|
||||||
{{- end -}}
|
{{- end }}
|
||||||
data-url="/edition/"
|
data-url="/edition/"
|
||||||
class="text-slate-600 hover:text-slate-900 hover:cursor-pointer hover:bg-slate-100
|
class="text-slate-600 hover:text-slate-900 hover:cursor-pointer hover:bg-slate-100
|
||||||
!pr-2.5"
|
!pr-2.5"
|
||||||
|
|||||||
@@ -29,29 +29,6 @@
|
|||||||
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
||||||
|
|
||||||
{{ if .isDev -}}
|
|
||||||
{{/* INFO: this runs airs injected script on page load, in dev mode */}}
|
|
||||||
{{/* INFO: Make sure airs proxy runs on port 8081 */}}
|
|
||||||
<script type="module">
|
|
||||||
function hookupAIR() {
|
|
||||||
const port = window.location.port;
|
|
||||||
if (!port || port !== "8081") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
document.body.addEventListener("htmx:afterSwap", (event) => {
|
|
||||||
if (event.detail.target === document.body) {
|
|
||||||
const scriptEl = document.querySelector("body > script:last-of-type");
|
|
||||||
if (scriptEl && scriptEl.textContent.trim()) {
|
|
||||||
new Function(scriptEl.textContent)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hookupAIR();
|
|
||||||
</script>
|
|
||||||
{{- end }}
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="w-full text-lg" hx-ext="response-targets" hx-boost="true">
|
<body class="w-full text-lg" hx-ext="response-targets" hx-boost="true">
|
||||||
@@ -68,10 +45,9 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="container-normal">
|
{{ block "_footer" . }}
|
||||||
{{ block "_footer" . }}
|
{{ end }}
|
||||||
{{ end }}
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<scroll-button></scroll-button>
|
<scroll-button></scroll-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
{{- $bd := index $entries $rel.Entry -}}
|
{{- $bd := index $entries $rel.Entry -}}
|
||||||
|
|
||||||
{{- if $bd -}}
|
{{- if $bd -}}
|
||||||
<div class="flex flex-row odd:bg-zinc-100 px-3 py-0.5 justify-between w-full">
|
<div class="flex flex-row odd:bg-zinc-100 px-3 ml-2 py-0.5 justify-between w-full">
|
||||||
<a href="/almanach/{{ $bd.MusenalmID }}" class="no-underline">
|
<a href="/almanach/{{ $bd.MusenalmID }}" class="no-underline">
|
||||||
<div class="">
|
<div class="">
|
||||||
{{- if $bd.PreferredTitle -}}
|
{{- if $bd.PreferredTitle -}}
|
||||||
|
|||||||
50
views/routes/components/_toc.gohtml
Normal file
50
views/routes/components/_toc.gohtml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{{ $toc := . }}
|
||||||
|
|
||||||
|
{{- if $toc -}}
|
||||||
|
<div class="block border text-base w-max">
|
||||||
|
<div class="text-sm py-1.5 italic bg-slate-100 px-4 border-b">Auf dieser Seite:</div>
|
||||||
|
{{- $h1cnt := 0 -}}
|
||||||
|
{{- $h2cnt := 0 -}}
|
||||||
|
{{- $h3cnt := 0 -}}
|
||||||
|
{{- $h4cnt := 0 -}}
|
||||||
|
{{- $h5cnt := 0 -}}
|
||||||
|
{{- $h6cnt := 0 -}}
|
||||||
|
<div class="py-2 px-4">
|
||||||
|
{{- range $i, $t := $toc -}}
|
||||||
|
<div class="">
|
||||||
|
{{- if eq $t.Level 1 -}}
|
||||||
|
{{- $h1cnt = Add $h1cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h1:nth-of-type({{- $h1cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- else if eq $t.Level 2 -}}
|
||||||
|
{{- $h2cnt = Add $h2cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h2:nth-of-type({{- $h2cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- else if eq $t.Level 3 -}}
|
||||||
|
{{- $h3cnt = Add $h3cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h3:nth-of-type({{- $h3cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- else if eq $t.Level 4 -}}
|
||||||
|
{{- $h4cnt = Add $h4cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h4:nth-of-type({{- $h4cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- else if eq $t.Level 5 -}}
|
||||||
|
{{- $h5cnt = Add $h5cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h5:nth-of-type({{- $h5cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- else if eq $t.Level 6 -}}
|
||||||
|
{{- $h6cnt = Add $h6cnt 1 -}}
|
||||||
|
<int-link data-jump=".jumptext h6:nth-of-type({{- $h6cnt -}})" class="font-serif"
|
||||||
|
>{{ $t.Title }}</int-link
|
||||||
|
>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
@@ -1 +1,238 @@
|
|||||||
Hello from Datenschutz
|
<div class="container-normal">
|
||||||
|
<div class="text [&_*]:!indent-0 border px-8 py-7">
|
||||||
|
<h1 class="!mt-0">Impressum</h1>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<strong>Telemedienanbieter im Sinne des § 5 TMG:</strong><br />Theodor Springmann
|
||||||
|
Stiftung<br />Hirschgasse 2<br />69120 Heidelberg<br /><br />Telefon +49 6221 436235<br />Email <a
|
||||||
|
href="mailto:info@theodor-springmann-stiftung.de"
|
||||||
|
>info@theodor-springmann-stiftung.de</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Rechtsform und Sitz:</strong><br />Die Theodor Springmann Stiftung ist eine
|
||||||
|
rechtsfähige Stiftung bürgerlichen Rechts. Sitz der Stiftung ist Heidelberg.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Vorstand der Theodor Springmann Stiftung:</strong><br />Dr. Randolf Straky
|
||||||
|
(Präsident)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Geschäftsführung:</strong><br />Dr. Randolf Straky<br />Theodor Springmann
|
||||||
|
Stiftung<br />Hirschgasse 2<br />69120 Heidelberg
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Zuständige Aufsichtsbehörde:</strong><br />Regierungspräsidium Karlsruhe<br />Schlossplatz
|
||||||
|
1-3<br />76131 Karlsruhe<br /><br /><a
|
||||||
|
href="https://rp.baden-wuerttemberg.de/Themen/Stiftung/Seiten/Ansprechpartner.aspx"
|
||||||
|
>Ansprechpartner</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Redaktionelle Verantwortung nach § 55 Abs. 2 RStV:</strong><br />Adrian
|
||||||
|
Braunbehrens<br />Theodor Springmann Stiftung<br />Hirschgasse 2<br />69120 Heidelberg
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
2024-10-17 09:52:17.412Z
|
||||||
|
</div>
|
||||||
|
<div class="text">
|
||||||
|
<h1 class="mt-12">Datenschutzerklärung</h1>
|
||||||
|
<div class="ma-prose-prose">
|
||||||
|
<div>
|
||||||
|
<h2>Präambel</h2>
|
||||||
|
<p>
|
||||||
|
Diese Datenschutzerklärung informiert Sie über die Art, den Umfang und den Zweck der
|
||||||
|
personenbezogenen Daten, die im Rahmen dieser Onlinepräsenz von Ihnen erhoben und von uns
|
||||||
|
verarbeitet werden, sowie die Ihnen zustehenden Rechte.<br />Personenbezogene Daten sind
|
||||||
|
alle Informationen, die sich auf eine identifizierte oder identifizierbare natürliche
|
||||||
|
Person beziehen. Als identifizierbar wird eine natürliche Person angesehen, die direkt
|
||||||
|
oder indirekt identifiziert werden kann. Im Hinblick auf weitere verwendete
|
||||||
|
Begrifflichkeiten verweisen wir auf die Definitionen der Datenschutz-Grundverordnung
|
||||||
|
(DSGVO), Artikel 4.<br />Erfolgt die Verarbeitung personenbezogener Daten auf Grundlage
|
||||||
|
des Art. 6 Abs. 1 lit. f DSGVO, so besteht unser berechtigtes Interesse in der Erfüllung
|
||||||
|
unseres satzungsgemäßen Stiftungszwecks. Zweck der Stiftung ist es, in gemeinnütziger
|
||||||
|
Weise Wissenschaft und Kunst, Völkerverständigung und Entwicklungshilfe zu fördern und zum
|
||||||
|
menschlichen Selbstverständnis sowie zum Erkennen und Lindern strukturell bedingter Not
|
||||||
|
und Bedürftigkeit von Menschen in aller Welt beizutragen.
|
||||||
|
</p>
|
||||||
|
<h2>Verantwortlicher</h2>
|
||||||
|
<p>
|
||||||
|
Verantwortlich im Sinne von Art. 4 Abs. 7 DSGVO für die Verarbeitung personenbezogener
|
||||||
|
Daten ist:<br />Theodor Springmann Stiftung<br />Hirschgasse 2<br />69120 Heidelberg<br /><br /><a
|
||||||
|
href="mailto:info@theodor-springmann-stiftung.de"
|
||||||
|
>info@theodor-springmann-stiftung.de</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<h2>Automatisch bei Nutzung unserer Onlinepräsenz erfasste Daten</h2>
|
||||||
|
<p>
|
||||||
|
Mit der Nutzung unserer Onlinepräsenz werden automatisch personenbezogene und allgemeine
|
||||||
|
Daten vom Nutzer übermittelt und von uns erfasst und gespeichert. Die von uns erhobenen
|
||||||
|
Daten umfassen:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
die IP-Adresse des ans Internet angeschlossenen Netzwerkgeräts (Computer oder Router des
|
||||||
|
Nutzers),
|
||||||
|
</li>
|
||||||
|
<li>den verwendeten Browsertyp und dessen Version,</li>
|
||||||
|
<li>das verwendete Betriebssystem und dessen Version,</li>
|
||||||
|
<li>die Internetseite, die den Nutzer auf unsere Onlinepräsenz verweist (Referrer),</li>
|
||||||
|
<li>die Unterwebseiten, die der Nutzer auf unserer Onlinepräsenz aufruft,</li>
|
||||||
|
<li>das Datum und die Uhrzeit des Aufrufs,</li>
|
||||||
|
<li>den Internet-Service-Provider des Nutzers,</li>
|
||||||
|
<li>sonstige ähnliche Daten.</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
Die Theodor Springmann Stiftung zieht aus diesen Daten keine Rückschlüsse auf die
|
||||||
|
betroffenen Nutzer. Diese Informationen werden benötigt, um
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>die vom Nutzer angeforderten Inhalte korrekt auszuliefern,</li>
|
||||||
|
<li>
|
||||||
|
technische Probleme zu diagnostizieren, unsere IT-Systeme vor Angriffen zu schützen und
|
||||||
|
im Falle eines Angriffs den zuständigen Behörden notwendige Informationen zur
|
||||||
|
Strafverfolgung bereitstellen zu können,
|
||||||
|
</li>
|
||||||
|
<li>die Inhalte und die Bedienung unserer Onlinepräsenz zu optimieren.</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
Die oben genannten Verarbeitungszwecke werden von Subsystemen erfüllt, die unabhängig von
|
||||||
|
anderen Subsystemen ihre jeweils eigene Kopie der vom Nutzer erhobenen Daten erhalten,
|
||||||
|
verarbeiten und löschen. Dabei werden den Subsystemen lediglich die zur Ausführung ihrer
|
||||||
|
Aufgabe erforderlichen Daten übergeben. Alle Subsysteme befinden sich auf Servern der
|
||||||
|
Theodor Springmann Stiftung.
|
||||||
|
</p>
|
||||||
|
<h3>Auslieferung der vom Nutzer angeforderten Inhalte</h3>
|
||||||
|
<p>
|
||||||
|
Mit der Anforderung einer Seite dieser Onlinepräsenz übermittelt der Browser des Nutzers
|
||||||
|
automatisch die IP-Adresse seines ans Internet angeschlossenen Netzwerkgeräts (Computer
|
||||||
|
oder Router) und andere Daten. Ohne diese IP-Adresse können die Inhalte dieser
|
||||||
|
Online-Präsenz nicht an den Nutzer zurückgesendet werden. Daher ist die Speicherung und
|
||||||
|
Verarbeitung der IP-Adresse für den Betrieb dieser Onlinepräsenz notwendig. Ebenfalls
|
||||||
|
übermittelte Daten über den verwendeten Browser usw. werden gegebenenfalls verwendet, um
|
||||||
|
die Anzeige der Webseite an das Anzeigegerät oder den Browser anzupassen. Die zum Zwecke
|
||||||
|
der Auslieferung von Inhalten gesammelten Daten werden direkt nach Übertragung der Inhalte
|
||||||
|
vom Subsystem gelöscht. Die Verarbeitung dieser Daten erfolgt auf der Grundlage eines
|
||||||
|
berechtigten Interesses nach Art. 6 Abs. 1 lit. f DSGVO.
|
||||||
|
</p>
|
||||||
|
<h3>Diagnose und Schutz der IT-Systeme</h3>
|
||||||
|
<p>
|
||||||
|
Daneben erfolgt eine Speicherung der oben genannten Daten in Diagnose-Protokollen. Die
|
||||||
|
Protokollierung ist notwendig, um etwaige technische Probleme analysieren oder Angriffe
|
||||||
|
erkennen und abwehren zu können. Bei Angriffen auf unsere IT-Systeme übergeben wir die
|
||||||
|
Diagnose-Protokolle den zuständigen Strafverfolgungsbehörden. Die Diagnose-Protokolle
|
||||||
|
werden nach 14 Tagen automatisch gelöscht. Die Speicherung und Verarbeitung dieser Daten
|
||||||
|
erfolgt auf Grundlage eines berechtigten Interesses nach Art. 6 Abs. 1 lit. f DSGVO.
|
||||||
|
</p>
|
||||||
|
<h3>Analyse zur Optimierung der Inhalte und der Bedienung</h3>
|
||||||
|
<p>
|
||||||
|
Die oben genannten Daten werden von einem Webanalyseprogramm verarbeitet. Dabei werden die
|
||||||
|
Daten pseudonymisiert und aggregiert, so dass sie einzelnen Nutzern nicht mehr zugeordnet
|
||||||
|
werden können. Das Analyseprogramm wird auf einem von uns betriebenen Server ausgeführt,
|
||||||
|
daher werden keine Daten an Dritte übermittelt. Der Zweck dieser Erfassung besteht in der
|
||||||
|
Analyse der Nutzung unseres Angebots, durch die eine Verbesserung unserer Webseiten, der
|
||||||
|
Inhalte und der Bedienung ermöglicht wird. Das Analyseprogramm speichert die
|
||||||
|
anonymisierten Daten ohne zeitliche Begrenzung. Die Verarbeitung dieser Daten erfolgt auf
|
||||||
|
der Grundlage eines berechtigten Interesses (Art. 6 Abs. 1 lit. f DSGVO).
|
||||||
|
</p>
|
||||||
|
<h2>Sonstige Daten</h2>
|
||||||
|
<p>
|
||||||
|
Sämtliche Daten, die mit dem Aufruf einer Webseite von unserer Onlinepräsenz an den Nutzer
|
||||||
|
übertragen werden, werden von unseren Servern bereitgestellt. Wir nutzen kein von Dritten
|
||||||
|
bereitgestelltes Content Delivery Network (CDN), um Teile unserer Onlinepräsenz (z. B.
|
||||||
|
Javascript- oder Webfont-Dateien) von dort an den Nutzer zu übermitteln. Wir verlinken
|
||||||
|
auch nicht in soziale Netzwerke. Insofern können von Dritten keine personenbezogenen Daten
|
||||||
|
über unsere Onlinepräsenz erhoben werden, es sei denn, die Datenerfassung durch Dritte
|
||||||
|
basiert auf einer gesetzlichen Grundlage und/oder wurde behördlich angeordnet.<br />In
|
||||||
|
unseren Inhalten können sich jedoch Hyperlinks („Links“) auf fremde Onlineangebote
|
||||||
|
befinden. Mit dem Anklicken eines solchen Links verlässt der Nutzer unsere Onlinepräsenz
|
||||||
|
und damit den Geltungsbereich dieser Datenschutzerklärung.
|
||||||
|
</p>
|
||||||
|
<h2>Erhobene Daten bei Kontakt</h2>
|
||||||
|
<p>
|
||||||
|
Unsere Onlinepräsenz hält unter anderem aufgrund gesetzlicher Vorgaben verschiedene
|
||||||
|
Möglichkeiten bereit, mit uns in Kontakt zu treten. Sofern eine betroffene Person Kontakt
|
||||||
|
zu uns aufnimmt, werden die von der betroffenen Person übermittelten personenbezogenen
|
||||||
|
Daten automatisch gespeichert (z. B. Telefonnummer, E-Mail-Adresse). Diese Angaben werden
|
||||||
|
zum Zwecke der Bearbeitung sowie für sich möglicherweise anschließende Kommunikation von
|
||||||
|
uns gespeichert. Sobald die Speicherung dieser Daten nicht mehr erforderlich ist und keine
|
||||||
|
gesetzlichen Archivierungsgründe vorliegen, werden die Daten gelöscht. Die
|
||||||
|
Erforderlichkeit wird alle zwei Jahre überprüft. Es erfolgt keine Weitergabe dieser
|
||||||
|
personenbezogenen Daten an Dritte.<br />Von betroffenen Personen übermittelte
|
||||||
|
Informationen zur Bearbeitung einer Kontaktanfrage werden gemäß Art. 6 Abs. 1 lit. b
|
||||||
|
(vertragliche und vorvertragliche Beziehungen) oder lit. f (andere Anfragen) der DSGVO
|
||||||
|
verarbeitet.
|
||||||
|
</p>
|
||||||
|
<h2>Speicherung und Löschung von personenbezogenen Daten</h2>
|
||||||
|
<p>
|
||||||
|
Personenbezogene Daten werden von uns für die Dauer der entsprechenden gesetzlichen
|
||||||
|
Aufbewahrungspflichten oder für den zur Vertragserfüllung erforderlichen Zeitraum
|
||||||
|
gespeichert. Liegen solche Gründe nicht vor, werden personenbezogene Daten für den
|
||||||
|
Zeitraum, der zur Erreichung des Speicherzwecks erforderlich ist, verarbeitet und
|
||||||
|
gespeichert, sofern in dieser Datenschutzerklärung nicht ausdrücklich anderes angegeben
|
||||||
|
ist. Sobald die Daten für ihre Zweckbestimmung nicht mehr erforderlich sind oder der
|
||||||
|
Speicherungszweck entfällt, werden sie nach Maßgabe der gesetzlichen Vorschriften gelöscht
|
||||||
|
oder in ihrer Verarbeitung eingeschränkt.<br />Sollten die Daten nicht gelöscht werden
|
||||||
|
dürfen, weil sie einer gesetzlichen Aufbewahrungspflicht unterliegen, wird deren
|
||||||
|
Verarbeitung durch Archivierung eingeschränkt. Die Daten werden erst nach Ablauf der
|
||||||
|
gesetzlich vorgeschriebenen Speicherfrist gelöscht.<br />Alle sechs Monate wird
|
||||||
|
routinemäßig geprüft, ob der Speicherungszweck weggefallen bzw. die Aufbewahrungspflicht
|
||||||
|
abgelaufen ist. Anschließend wird gegebenenfalls die Löschung durchgeführt.
|
||||||
|
</p>
|
||||||
|
<h2>Rechte der betroffenen Personen</h2>
|
||||||
|
<p>
|
||||||
|
Unter den angegebenen Kontaktdaten können betroffene Personen jederzeit nachgenannte
|
||||||
|
Rechte ausüben. Eine betroffene Person kann von uns verlangen, dass
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Auskunft über sie betreffende, bei uns gespeicherte Daten und deren Verarbeitung erteilt
|
||||||
|
wird (Art. 15 DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
sie betreffende unrichtige personenbezogene Daten berichtigt werden (Art. 16 DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
sie betreffende, bei uns gespeicherte personenbezogene Daten gelöscht werden (Art. 17
|
||||||
|
DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
die Verarbeitung sie betreffender, bei uns gespeicherter Daten, die aufgrund
|
||||||
|
gesetzlicher Vorschriften oder anderer Gründe nicht gelöscht werden dürfen,
|
||||||
|
eingeschränkt wird (Art. 18 DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
sie betreffende Daten übertragbar sind, soweit sie in die Datenverarbeitung eingewilligt
|
||||||
|
oder einen Vertrag mit uns geschlossen hat (Art. 20 DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
sie betreffende Daten nach einem Widerspruch nicht weiter von uns verarbeitet werden
|
||||||
|
(Art. 21 DSGVO).
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>Eine betroffene Person hat ferner jederzeit das Recht,</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
eine erteilte Einwilligung in die Erhebung und Verarbeitung personenbezogener Daten nach
|
||||||
|
Art. 6 Abs. 1 lit. a oder Art. 9 Abs. 2 lit. a DSGVO für die Zukunft zu widerrufen (Art.
|
||||||
|
7 Abs. 3 DSGVO),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
sich mit einer Beschwerde an eine Aufsichtsbehörde zu wenden (Art. 15 Abs. 1 lit. f
|
||||||
|
DSGVO). Eine Liste der Aufsichtsbehörden lässt sich unter <a
|
||||||
|
href="https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html"
|
||||||
|
>diesem Link</a
|
||||||
|
> abrufen.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2>Änderung unserer Datenschutzerklärung</h2>
|
||||||
|
<p>
|
||||||
|
Wir behalten uns vor, diese Datenschutzerklärung ohne vorherige Ankündigung an neue
|
||||||
|
rechtliche oder technische Sachverhalte sowie an Änderungen unserer Leistungen oder
|
||||||
|
Prozesse anzupassen. Es gilt die jeweils auf der Onlinepräsenz veröffentlichte Version der
|
||||||
|
Datenschutzerklärung.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<div class="container-normal">
|
<div class="container-normal relative">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
{{ Safe .record.Text }}
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
|
<div class="text [&_*]:!indent-0 [&_p]:mt-2">
|
||||||
|
{{ Safe .record.Text }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.title }}</title>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<div class="container-normal relative">
|
||||||
|
<div class="text">
|
||||||
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
|
<div class="text">
|
||||||
|
{{ Safe .record.Text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.Title }}</title>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.Title }}</title>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<div class="container-normal">
|
<div class="container-normal relative">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
{{ Safe .record.Text }}
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
|
<div class="text [&_*]:!indent-0 [&_p]:mt-2">
|
||||||
|
{{ Safe .record.Text }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.Title }}</title>
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
<div class="container-normal">
|
{{ $toc := TOCFromHTML .record.Text }}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container-normal relative">
|
||||||
<div class="text indented">
|
<div class="text indented">
|
||||||
{{ Safe .record.Text }}
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
|
<div class="flex flex-row gap-x-6 justify-between">
|
||||||
|
<div class="jumptext grow shrink-0">
|
||||||
|
{{ Safe .record.Text }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{- if $toc -}}
|
||||||
|
<div class="xl:sticky xl:top-8 grow-0">
|
||||||
|
{{- template "_toc" $toc -}}
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.Title }}</title>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<title>Musenalm - Reihen</title>
|
<title>{{ .site.title }} – Reihen</title>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const FILTER_LIST_SEARCHABLE = "filter-list-searchable";
|
|||||||
const SCROLL_BUTTON_ELEMENT = "scroll-button";
|
const SCROLL_BUTTON_ELEMENT = "scroll-button";
|
||||||
const TOOLTIP_ELEMENT = "tool-tip";
|
const TOOLTIP_ELEMENT = "tool-tip";
|
||||||
const ABBREV_TOOLTIPS_ELEMENT = "abbrev-tooltips";
|
const ABBREV_TOOLTIPS_ELEMENT = "abbrev-tooltips";
|
||||||
|
const INT_LINK_ELEMENT = "int-link";
|
||||||
|
|
||||||
class XSLTParseProcess {
|
class XSLTParseProcess {
|
||||||
#processors;
|
#processors;
|
||||||
@@ -738,6 +739,35 @@ class AbbreviationTooltips extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IntLink extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
// Basic styling to mimic a link.
|
||||||
|
this.style.cursor = "pointer";
|
||||||
|
this.addEventListener("click", this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
this.removeEventListener("click", this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick(event) {
|
||||||
|
const selector = this.getAttribute("data-jump");
|
||||||
|
if (selector) {
|
||||||
|
const target = document.querySelector(selector);
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: "smooth" });
|
||||||
|
} else {
|
||||||
|
console.warn(`No element found for selector: ${selector}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define(INT_LINK_ELEMENT, IntLink);
|
||||||
customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
|
customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
|
||||||
customElements.define(FILTER_LIST_ELEMENT, FilterList);
|
customElements.define(FILTER_LIST_ELEMENT, FilterList);
|
||||||
customElements.define(SCROLL_BUTTON_ELEMENT, ScrollButton);
|
customElements.define(SCROLL_BUTTON_ELEMENT, ScrollButton);
|
||||||
|
|||||||
@@ -167,11 +167,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
@apply font-serif max-w-[48rem];
|
@apply font-serif hyphens-auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text p {
|
.text p {
|
||||||
@apply text-lg hyphens-auto;
|
@apply text-lg hyphens-auto max-w-[70ch];
|
||||||
|
}
|
||||||
|
|
||||||
|
.text ul {
|
||||||
|
@apply list-disc ml-0 max-w-[70ch];
|
||||||
|
}
|
||||||
|
|
||||||
|
.text ol {
|
||||||
|
@apply list-decimal ml-0 max-w-[70ch];
|
||||||
}
|
}
|
||||||
|
|
||||||
.text p:first-of-type {
|
.text p:first-of-type {
|
||||||
@@ -190,6 +198,18 @@
|
|||||||
@apply mt-1;
|
@apply mt-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text h1 {
|
||||||
|
@apply text-3xl font-bold mt-6 mb-1.5 hyphens-none leading-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text h2 {
|
||||||
|
@apply text-xl font-bold mt-3 mb-1.5 hyphens-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text h3 {
|
||||||
|
@apply text-lg font-bold mt-3 mb-1.5 hyphens-none;
|
||||||
|
}
|
||||||
|
|
||||||
.text p + ol {
|
.text p + ol {
|
||||||
@apply mt-1;
|
@apply mt-1;
|
||||||
}
|
}
|
||||||
@@ -203,7 +223,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text p + p:not(.indented p, p:first-of-type) {
|
.text p + p:not(.indented p, p:first-of-type) {
|
||||||
@apply indent-3.5;
|
@apply indent-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.indented p {
|
.indented p {
|
||||||
@@ -327,4 +347,8 @@
|
|||||||
|
|
||||||
#entrydata {
|
#entrydata {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int-link {
|
||||||
|
@apply text-slate-700 hover:text-slate-900 underline decoration-dotted hover:decoration-solid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user