mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-29 09:05:30 +00:00
Verbesserungen kategoireansicht, karte aof ortsansicht
This commit is contained in:
@@ -29,8 +29,8 @@ class $ extends HTMLElement {
|
|||||||
if (!i)
|
if (!i)
|
||||||
return;
|
return;
|
||||||
i.querySelectorAll(".person-item").forEach((s) => {
|
i.querySelectorAll(".person-item").forEach((s) => {
|
||||||
var c, d;
|
var c, h;
|
||||||
const o = ((c = s.querySelector(".person-name")) == null ? void 0 : c.textContent) || "", r = ((d = s.querySelector(".person-life")) == null ? void 0 : d.textContent) || "";
|
const o = ((c = s.querySelector(".person-name")) == null ? void 0 : c.textContent) || "", r = ((h = s.querySelector(".person-life")) == null ? void 0 : h.textContent) || "";
|
||||||
!e || o.toLowerCase().includes(e) || r.toLowerCase().includes(e) ? s.style.display = "block" : s.style.display = "none";
|
!e || o.toLowerCase().includes(e) || r.toLowerCase().includes(e) ? s.style.display = "block" : s.style.display = "none";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ class O extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("place-jump-filter", O);
|
customElements.define("place-jump-filter", O);
|
||||||
class V extends HTMLElement {
|
class R extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const e = this.querySelector("#category-search");
|
const e = this.querySelector("#category-search");
|
||||||
e && e.addEventListener("input", (t) => {
|
e && e.addEventListener("input", (t) => {
|
||||||
@@ -63,8 +63,8 @@ class V extends HTMLElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("category-jump-filter", V);
|
customElements.define("category-jump-filter", R);
|
||||||
class R extends HTMLElement {
|
class V extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.issuesByYear = {};
|
super(), this.issuesByYear = {};
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ class R extends HTMLElement {
|
|||||||
i.disabled = !o;
|
i.disabled = !o;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("year-jump-filter", R);
|
customElements.define("year-jump-filter", V);
|
||||||
class z extends HTMLElement {
|
class z extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.isOpen = !1;
|
super(), this.isOpen = !1;
|
||||||
@@ -339,9 +339,9 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
});
|
});
|
||||||
const k = [];
|
const k = [];
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
I();
|
H();
|
||||||
});
|
});
|
||||||
const I = function() {
|
const H = function() {
|
||||||
for (; k.length > 0; ) {
|
for (; k.length > 0; ) {
|
||||||
const a = k.shift();
|
const a = k.shift();
|
||||||
try {
|
try {
|
||||||
@@ -425,18 +425,18 @@ class F extends HTMLElement {
|
|||||||
const s = n.getAttribute("id"), o = n.querySelector(".akteur-werke-section"), r = n.querySelector(".akteur-beitraege-section");
|
const s = n.getAttribute("id"), o = n.querySelector(".akteur-werke-section"), r = n.querySelector(".akteur-beitraege-section");
|
||||||
let l = !1;
|
let l = !1;
|
||||||
if (o) {
|
if (o) {
|
||||||
const c = o.getBoundingClientRect(), d = c.top < window.innerHeight, u = c.bottom > 0;
|
const c = o.getBoundingClientRect(), h = c.top < window.innerHeight, d = c.bottom > 0;
|
||||||
d && u && (l = !0);
|
h && d && (l = !0);
|
||||||
}
|
}
|
||||||
if (r && !l) {
|
if (r && !l) {
|
||||||
const c = r.getBoundingClientRect(), d = c.top < window.innerHeight, u = c.bottom > 0;
|
const c = r.getBoundingClientRect(), h = c.top < window.innerHeight, d = c.bottom > 0;
|
||||||
d && u && (l = !0);
|
h && d && (l = !0);
|
||||||
}
|
}
|
||||||
if (!o && !r) {
|
if (!o && !r) {
|
||||||
const c = n.querySelector("div:first-child");
|
const c = n.querySelector("div:first-child");
|
||||||
if (c) {
|
if (c) {
|
||||||
const d = c.getBoundingClientRect(), u = d.top >= 0, h = d.bottom <= window.innerHeight;
|
const h = c.getBoundingClientRect(), d = h.top >= 0, u = h.bottom <= window.innerHeight;
|
||||||
u && h && (l = !0);
|
d && u && (l = !0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l && e.push(s);
|
l && e.push(s);
|
||||||
@@ -453,8 +453,8 @@ class F extends HTMLElement {
|
|||||||
const n = document.getElementById("scrollspy-nav"), s = n.getBoundingClientRect();
|
const n = document.getElementById("scrollspy-nav"), s = n.getBoundingClientRect();
|
||||||
let o = 1 / 0, r = -1 / 0;
|
let o = 1 / 0, r = -1 / 0;
|
||||||
t.forEach((c) => {
|
t.forEach((c) => {
|
||||||
const d = c.getBoundingClientRect(), u = d.top - s.top + n.scrollTop, h = u + d.height;
|
const h = c.getBoundingClientRect(), d = h.top - s.top + n.scrollTop, u = d + h.height;
|
||||||
o = Math.min(o, u), r = Math.max(r, h);
|
o = Math.min(o, d), r = Math.max(r, u);
|
||||||
});
|
});
|
||||||
let l = r - o;
|
let l = r - o;
|
||||||
i.style.top = `${o}px`, i.style.height = `${l}px`, i.style.opacity = "1", setTimeout(() => this.ensureMarkerVisibility(), 100);
|
i.style.top = `${o}px`, i.style.height = `${l}px`, i.style.opacity = "1", setTimeout(() => this.ensureMarkerVisibility(), 100);
|
||||||
@@ -490,9 +490,9 @@ class F extends HTMLElement {
|
|||||||
document.documentElement.clientHeight,
|
document.documentElement.clientHeight,
|
||||||
document.documentElement.scrollHeight,
|
document.documentElement.scrollHeight,
|
||||||
document.documentElement.offsetHeight
|
document.documentElement.offsetHeight
|
||||||
), s = window.innerHeight, o = n - s, r = o > 0 ? window.scrollY / o : 0, l = t.clientHeight, d = t.scrollHeight - l;
|
), s = window.innerHeight, o = n - s, r = o > 0 ? window.scrollY / o : 0, l = t.clientHeight, h = t.scrollHeight - l;
|
||||||
if (d > 0) {
|
if (h > 0) {
|
||||||
const u = r * d, h = i.getBoundingClientRect(), p = t.getBoundingClientRect(), b = h.top - p.top + t.scrollTop, g = l / 2, y = b - g, w = 0.7, x = w * u + (1 - w) * y, v = Math.max(0, Math.min(d, x)), E = t.scrollTop;
|
const d = r * h, u = i.getBoundingClientRect(), p = t.getBoundingClientRect(), m = u.top - p.top + t.scrollTop, g = l / 2, w = m - g, x = 0.7, f = x * d + (1 - x) * w, v = Math.max(0, Math.min(h, f)), E = t.scrollTop;
|
||||||
Math.abs(v - E) > 10 && t.scrollTo({
|
Math.abs(v - E) > 10 && t.scrollTo({
|
||||||
top: v,
|
top: v,
|
||||||
behavior: "smooth"
|
behavior: "smooth"
|
||||||
@@ -566,7 +566,7 @@ class j extends HTMLElement {
|
|||||||
this.countElement && (t === "" ? this.countElement.textContent = `Alle Orte (${this.originalCount})` : e === 0 ? this.countElement.textContent = `Keine Orte gefunden für "${t}"` : this.countElement.textContent = `${e} von ${this.originalCount} Orten`);
|
this.countElement && (t === "" ? this.countElement.textContent = `Alle Orte (${this.originalCount})` : e === 0 ? this.countElement.textContent = `Keine Orte gefunden für "${t}"` : this.countElement.textContent = `${e} von ${this.originalCount} Orten`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class K extends HTMLElement {
|
class _ extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.isExpanded = !1, this.isLoading = !1, this.hasLoaded = !1, this.boundHandleClick = this.handleClick.bind(this), this.boundHandleMapClick = this.handleMapClick.bind(this), this.boundHandleHeadingHover = this.handleHeadingHover.bind(this), this.boundHandleHeadingLeave = this.handleHeadingLeave.bind(this);
|
super(), this.isExpanded = !1, this.isLoading = !1, this.hasLoaded = !1, this.boundHandleClick = this.handleClick.bind(this), this.boundHandleMapClick = this.handleMapClick.bind(this), this.boundHandleHeadingHover = this.handleHeadingHover.bind(this), this.boundHandleHeadingLeave = this.handleHeadingLeave.bind(this);
|
||||||
}
|
}
|
||||||
@@ -707,10 +707,10 @@ class W extends HTMLElement {
|
|||||||
if (!this.places.length || !this.pointsContainer)
|
if (!this.places.length || !this.pointsContainer)
|
||||||
return;
|
return;
|
||||||
const e = { xmin: 2555e3, ymin: 135e4, xmax: 7405e3, ymax: 55e5 }, t = { lon: 10, lat: 52 }, i = (s, o) => {
|
const e = { xmin: 2555e3, ymin: 135e4, xmax: 7405e3, ymax: 55e5 }, t = { lon: 10, lat: 52 }, i = (s, o) => {
|
||||||
const d = t.lon * Math.PI / 180, u = t.lat * Math.PI / 180, h = o * Math.PI / 180, p = s * Math.PI / 180, b = Math.sqrt(
|
const h = t.lon * Math.PI / 180, d = t.lat * Math.PI / 180, u = o * Math.PI / 180, p = s * Math.PI / 180, m = Math.sqrt(
|
||||||
2 / (1 + Math.sin(u) * Math.sin(p) + Math.cos(u) * Math.cos(p) * Math.cos(h - d))
|
2 / (1 + Math.sin(d) * Math.sin(p) + Math.cos(d) * Math.cos(p) * Math.cos(u - h))
|
||||||
), g = 6371e3 * b * Math.cos(p) * Math.sin(h - d), y = 6371e3 * b * (Math.cos(u) * Math.sin(p) - Math.sin(u) * Math.cos(p) * Math.cos(h - d)), w = g + 4321e3, x = y + 321e4, v = e.xmax - e.xmin, E = e.ymax - e.ymin, L = (w - e.xmin) / v * 100, C = (e.ymax - x) / E * 100;
|
), g = 6371e3 * m * Math.cos(p) * Math.sin(u - h), w = 6371e3 * m * (Math.cos(d) * Math.sin(p) - Math.sin(d) * Math.cos(p) * Math.cos(u - h)), x = g + 4321e3, f = w + 321e4, v = e.xmax - e.xmin, E = e.ymax - e.ymin, S = (x - e.xmin) / v * 100, L = (e.ymax - f) / E * 100;
|
||||||
return { x: L, y: C };
|
return { x: S, y: L };
|
||||||
}, n = [];
|
}, n = [];
|
||||||
this.places.forEach((s) => {
|
this.places.forEach((s) => {
|
||||||
if (s.lat && s.lng) {
|
if (s.lat && s.lng) {
|
||||||
@@ -719,8 +719,8 @@ class W extends HTMLElement {
|
|||||||
n.push(l);
|
n.push(l);
|
||||||
const c = document.createElement("div");
|
const c = document.createElement("div");
|
||||||
c.className = "map-point hidden", c.style.left = `${l.x}%`, c.style.top = `${l.y}%`, c.style.transformOrigin = "center";
|
c.className = "map-point hidden", c.style.left = `${l.x}%`, c.style.top = `${l.y}%`, c.style.transformOrigin = "center";
|
||||||
const d = `${s.name}${s.toponymName && s.toponymName !== s.name ? ` (${s.toponymName})` : ""}`;
|
const h = `${s.name}${s.toponymName && s.toponymName !== s.name ? ` (${s.toponymName})` : ""}`;
|
||||||
c.dataset.placeId = s.id, c.dataset.tooltipText = d, c.addEventListener("mouseenter", (u) => this.showTooltip(u)), c.addEventListener("mouseleave", () => this.hideTooltip()), c.addEventListener("mousemove", (u) => this.updateTooltipPosition(u)), c.addEventListener("click", (u) => this.scrollToPlace(u)), this.pointsContainer.appendChild(c), this.mapPoints.set(s.id, c);
|
c.dataset.placeId = s.id, c.dataset.tooltipText = h, c.addEventListener("mouseenter", (d) => this.showTooltip(d)), c.addEventListener("mouseleave", () => this.hideTooltip()), c.addEventListener("mousemove", (d) => this.updateTooltipPosition(d)), c.addEventListener("click", (d) => this.scrollToPlace(d)), this.pointsContainer.appendChild(c), this.mapPoints.set(s.id, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}), n.length > 0 && this.autoZoomToPoints(n);
|
}), n.length > 0 && this.autoZoomToPoints(n);
|
||||||
@@ -728,20 +728,20 @@ class W extends HTMLElement {
|
|||||||
// Calculate bounding box of all points for the auto-zoom
|
// Calculate bounding box of all points for the auto-zoom
|
||||||
autoZoomToPoints(e) {
|
autoZoomToPoints(e) {
|
||||||
let t = 100, i = 0, n = 100, s = 0;
|
let t = 100, i = 0, n = 100, s = 0;
|
||||||
e.forEach((f) => {
|
e.forEach((y) => {
|
||||||
f.x < t && (t = f.x), f.x > i && (i = f.x), f.y < n && (n = f.y), f.y > s && (s = f.y);
|
y.x < t && (t = y.x), y.x > i && (i = y.x), y.y < n && (n = y.y), y.y > s && (s = y.y);
|
||||||
});
|
});
|
||||||
const o = 0.06, r = i - t, l = s - n, c = r * o, d = l * o, u = Math.max(0, t - c), h = Math.min(100, i + c), p = Math.max(0, n - d), b = Math.min(100, s + d), g = h - u, y = b - p, w = 5 / 7, x = g / y;
|
const o = 0.06, r = i - t, l = s - n, c = r * o, h = l * o, d = Math.max(0, t - c), u = Math.min(100, i + c), p = Math.max(0, n - h), m = Math.min(100, s + h), g = u - d, w = m - p, x = 5 / 7, f = g / w;
|
||||||
let v = { x: u, y: p, width: g, height: y };
|
let v = { x: d, y: p, width: g, height: w };
|
||||||
if (x > w) {
|
if (f > x) {
|
||||||
const f = g / w;
|
const y = g / x;
|
||||||
v.y = p - (f - y) / 2, v.height = f;
|
v.y = p - (y - w) / 2, v.height = y;
|
||||||
} else {
|
} else {
|
||||||
const f = y * w;
|
const y = w * x;
|
||||||
v.x = u - (f - g) / 2, v.width = f;
|
v.x = d - (y - g) / 2, v.width = y;
|
||||||
}
|
}
|
||||||
const E = 100 / v.width, L = -v.x, C = -v.y, N = `scale(${E}) translate(${L}%, ${C}%)`, P = this.querySelector(".transform-wrapper");
|
const E = 100 / v.width, S = -v.x, L = -v.y, T = `scale(${E}) translate(${S}%, ${L}%)`, P = this.querySelector(".transform-wrapper");
|
||||||
P && (P.style.transform = N);
|
P && (P.style.transform = T);
|
||||||
}
|
}
|
||||||
initializeScrollspy() {
|
initializeScrollspy() {
|
||||||
const e = document.querySelectorAll("place-accordion[data-place-id]");
|
const e = document.querySelectorAll("place-accordion[data-place-id]");
|
||||||
@@ -755,19 +755,14 @@ class W extends HTMLElement {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Trigger when element enters viewport
|
// Trigger when any part enters viewport - better for small elements
|
||||||
threshold: 0.1,
|
threshold: 0,
|
||||||
// No root margin for precise detection
|
// Add some margin to trigger slightly before/after entering viewport
|
||||||
rootMargin: "0px"
|
rootMargin: "10px 0px"
|
||||||
}
|
}
|
||||||
), e.forEach((t) => {
|
), e.forEach((t) => {
|
||||||
this.intersectionObserver.observe(t);
|
this.intersectionObserver.observe(t);
|
||||||
}), setTimeout(() => {
|
}));
|
||||||
e.forEach((t) => {
|
|
||||||
const i = t.getBoundingClientRect(), n = i.top < window.innerHeight && i.bottom > 0, s = t.getAttribute("data-place-id"), o = this.mapPoints.get(s);
|
|
||||||
o && n && this.setPointActive(o);
|
|
||||||
});
|
|
||||||
}, 50));
|
|
||||||
}
|
}
|
||||||
setPointActive(e) {
|
setPointActive(e) {
|
||||||
e.className = "map-point absolute w-1.5 h-1.5 bg-red-500 border border-red-700 rounded-full shadow-md -translate-x-1/2 -translate-y-1/2 transition-all duration-300 opacity-100 saturate-100 z-20 cursor-pointer hover:w-2 hover:h-2 hover:bg-red-600 hover:z-30";
|
e.className = "map-point absolute w-1.5 h-1.5 bg-red-500 border border-red-700 rounded-full shadow-md -translate-x-1/2 -translate-y-1/2 transition-all duration-300 opacity-100 saturate-100 z-20 cursor-pointer hover:w-2 hover:h-2 hover:bg-red-600 hover:z-30";
|
||||||
@@ -832,29 +827,102 @@ class W extends HTMLElement {
|
|||||||
}
|
}
|
||||||
handleHeadingHoverEvent(e) {
|
handleHeadingHoverEvent(e) {
|
||||||
const { placeId: t, action: i } = e.detail, n = this.mapPoints.get(t);
|
const { placeId: t, action: i } = e.detail, n = this.mapPoints.get(t);
|
||||||
if (n)
|
n && (i === "show" ? (this.currentHoveredPlaceId = t, n.classList.remove("w-1", "h-1", "w-1.5", "h-1.5"), n.classList.add("w-2.5", "h-2.5"), n.style.zIndex = "25") : i === "hide" && (this.currentHoveredPlaceId = "", n.classList.remove("w-2.5", "h-2.5"), n.className.includes("bg-red-500") ? n.classList.add("w-1.5", "h-1.5") : n.classList.add("w-1", "h-1"), n.style.zIndex = ""));
|
||||||
if (i === "show") {
|
|
||||||
if (this.currentHoveredPlaceId = t, n.classList.remove("w-1", "h-1", "w-1.5", "h-1.5"), n.classList.add("w-2", "h-2"), n.style.zIndex = "25", this.isNewPopupBlocked(t))
|
|
||||||
return;
|
|
||||||
const s = n.dataset.tooltipText;
|
|
||||||
if (this.tooltip && s) {
|
|
||||||
this.tooltip.textContent = s;
|
|
||||||
const o = n.getBoundingClientRect(), r = this.mapElement.getBoundingClientRect(), l = o.left - r.left + o.width / 2, c = o.top - r.top + o.height / 2;
|
|
||||||
this.tooltip.style.left = `${l}px`, this.tooltip.style.top = `${c}px`, this.clearTimeouts(), this.isTooltipVisible ? (this.tooltip.classList.remove("opacity-0"), this.tooltip.classList.add("opacity-100")) : this.showTimeout = setTimeout(() => {
|
|
||||||
this.tooltip.classList.remove("opacity-0"), this.tooltip.classList.add("opacity-100"), this.isTooltipVisible = !0;
|
|
||||||
}, 150);
|
|
||||||
}
|
|
||||||
} else i === "hide" && (this.currentHoveredPlaceId = "", this.clearTimeouts(), this.hideTimeout = setTimeout(() => {
|
|
||||||
this.tooltip && (this.tooltip.classList.remove("opacity-100"), this.tooltip.classList.add("opacity-0"), this.isTooltipVisible = !1);
|
|
||||||
}, 150), n.classList.remove("w-2", "h-2"), n.className.includes("bg-red-500") ? n.classList.add("w-1.5", "h-1.5") : n.classList.add("w-1", "h-1"), n.style.zIndex = "");
|
|
||||||
}
|
}
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.intersectionObserver && (this.intersectionObserver.disconnect(), this.intersectionObserver = null), this.clearTimeouts(), document.removeEventListener("place-heading-hover", this.boundHandleHeadingHoverEvent), window.removeEventListener("scroll", this.boundHandleScroll), document.removeEventListener("scroll", this.boundHandleScroll);
|
this.intersectionObserver && (this.intersectionObserver.disconnect(), this.intersectionObserver = null), this.clearTimeouts(), document.removeEventListener("place-heading-hover", this.boundHandleHeadingHoverEvent), window.removeEventListener("scroll", this.boundHandleScroll), document.removeEventListener("scroll", this.boundHandleScroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class K extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super(), this.place = null, this.mapElement = null, this.pointsContainer = null, this.tooltip = null;
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.parseData(), this.render(), this.initializeMap();
|
||||||
|
}
|
||||||
|
parseData() {
|
||||||
|
try {
|
||||||
|
const e = this.dataset.place;
|
||||||
|
e && (this.place = JSON.parse(e));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse place data:", e), this.place = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
this.innerHTML = `
|
||||||
|
<div class="map-container relative w-full aspect-[5/7] overflow-hidden bg-slate-100">
|
||||||
|
<div class="transform-wrapper absolute top-0 left-0 w-full h-auto origin-top-left">
|
||||||
|
<img src="/assets/Europe.svg" alt="Map of Europe" class="block w-full h-auto">
|
||||||
|
<div class="points-container absolute top-0 left-0 w-full h-full"></div>
|
||||||
|
</div>
|
||||||
|
<div class="absolute bottom-0 right-0 h-auto text-[0.6rem] bg-white px-0.5 bg-opacity-[0.5] border">
|
||||||
|
<i class="ri-creative-commons-line"></i>
|
||||||
|
<a href="https://commons.wikimedia.org/wiki/File:Europe_laea_topography.svg" target="_blank" class="">
|
||||||
|
Wikimedia Commons
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Tooltip -->
|
||||||
|
<div class="map-tooltip absolute bg-slate-800 text-white text-sm px-2 py-1 rounded shadow-lg pointer-events-none opacity-0 transition-opacity duration-200 z-30 whitespace-nowrap" style="transform: translate(-50%, -100%); margin-top: -8px;"></div>
|
||||||
|
</div>
|
||||||
|
`, this.mapElement = this.querySelector(".map-container"), this.pointsContainer = this.querySelector(".points-container"), this.tooltip = this.querySelector(".map-tooltip");
|
||||||
|
}
|
||||||
|
initializeMap() {
|
||||||
|
if (!this.place || !this.place.lat || !this.place.lng || !this.pointsContainer)
|
||||||
|
return;
|
||||||
|
const e = { xmin: 2555e3, ymin: 135e4, xmax: 7405e3, ymax: 55e5 }, t = { lon: 10, lat: 52 }, i = (r, l) => {
|
||||||
|
const u = t.lon * Math.PI / 180, p = t.lat * Math.PI / 180, m = l * Math.PI / 180, g = r * Math.PI / 180, w = Math.sqrt(
|
||||||
|
2 / (1 + Math.sin(p) * Math.sin(g) + Math.cos(p) * Math.cos(g) * Math.cos(m - u))
|
||||||
|
), x = 6371e3 * w * Math.cos(g) * Math.sin(m - u), f = 6371e3 * w * (Math.cos(p) * Math.sin(g) - Math.sin(p) * Math.cos(g) * Math.cos(m - u)), v = x + 4321e3, E = f + 321e4, S = e.xmax - e.xmin, L = e.ymax - e.ymin, T = (v - e.xmin) / S * 100, P = (e.ymax - E) / L * 100;
|
||||||
|
return { x: T, y: P };
|
||||||
|
}, n = parseFloat(this.place.lat), s = parseFloat(this.place.lng), o = i(n, s);
|
||||||
|
if (o.x >= 0 && o.x <= 100 && o.y >= 0 && o.y <= 100) {
|
||||||
|
const r = document.createElement("div");
|
||||||
|
r.style.left = `${o.x}%`, r.style.top = `${o.y}%`, r.style.transformOrigin = "center", r.className = "absolute w-2 h-2 bg-red-500 border border-red-700 rounded-full shadow-md -translate-x-1/2 -translate-y-1/2 z-20";
|
||||||
|
const l = `${this.place.name}${this.place.toponymName && this.place.toponymName !== this.place.name ? ` (${this.place.toponymName})` : ""}`;
|
||||||
|
r.dataset.tooltipText = l, r.addEventListener("mouseenter", (c) => this.showTooltip(c)), r.addEventListener("mouseleave", () => this.hideTooltip()), r.addEventListener("mousemove", (c) => this.updateTooltipPosition(c)), this.pointsContainer.appendChild(r), this.autoZoomToPoint(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autoZoomToPoint(e) {
|
||||||
|
let i = Math.max(0, e.x - 20), n = Math.min(100, e.x + 20), s = Math.max(0, e.y - 20), o = Math.min(100, e.y + 20), r = n - i, l = o - s;
|
||||||
|
const c = 5 / 7, h = r / l;
|
||||||
|
let d = { x: i, y: s, width: r, height: l };
|
||||||
|
if (h > c) {
|
||||||
|
const f = r / c;
|
||||||
|
d.y = s - (f - l) / 2, d.height = f;
|
||||||
|
} else {
|
||||||
|
const f = l * c;
|
||||||
|
d.x = i - (f - r) / 2, d.width = f;
|
||||||
|
}
|
||||||
|
d.x < 0 && (d.width += d.x, d.x = 0), d.y < 0 && (d.height += d.y, d.y = 0), d.x + d.width > 100 && (d.width = 100 - d.x), d.y + d.height > 100 && (d.height = 100 - d.y);
|
||||||
|
const u = 30;
|
||||||
|
if (d.width < u) {
|
||||||
|
const f = (u - d.width) / 2;
|
||||||
|
d.x = Math.max(0, d.x - f), d.width = Math.min(u, 100 - d.x);
|
||||||
|
}
|
||||||
|
if (d.height < u) {
|
||||||
|
const f = (u - d.height) / 2;
|
||||||
|
d.y = Math.max(0, d.y - f), d.height = Math.min(u, 100 - d.y);
|
||||||
|
}
|
||||||
|
const p = 100 / d.width, m = -d.x, g = -d.y, w = `scale(${p}) translate(${m}%, ${g}%)`, x = this.querySelector(".transform-wrapper");
|
||||||
|
x && (x.style.transform = w);
|
||||||
|
}
|
||||||
|
showTooltip(e) {
|
||||||
|
const i = e.target.dataset.tooltipText;
|
||||||
|
this.tooltip && i && (this.tooltip.textContent = i, this.updateTooltipPosition(e), this.tooltip.classList.remove("opacity-0"), this.tooltip.classList.add("opacity-100"));
|
||||||
|
}
|
||||||
|
hideTooltip() {
|
||||||
|
this.tooltip && (this.tooltip.classList.remove("opacity-100"), this.tooltip.classList.add("opacity-0"));
|
||||||
|
}
|
||||||
|
updateTooltipPosition(e) {
|
||||||
|
if (!this.tooltip) return;
|
||||||
|
const t = this.mapElement.getBoundingClientRect(), i = e.clientX - t.left, n = e.clientY - t.top;
|
||||||
|
this.tooltip.style.left = `${i}px`, this.tooltip.style.top = `${n}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
customElements.define("places-filter", j);
|
customElements.define("places-filter", j);
|
||||||
customElements.define("place-accordion", K);
|
customElements.define("place-accordion", _);
|
||||||
customElements.define("places-map", W);
|
customElements.define("places-map", W);
|
||||||
|
customElements.define("places-map-single", K);
|
||||||
class Y extends HTMLElement {
|
class Y extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.searchInput = null, this.itemCards = [], this.countElement = null, this.debounceTimer = null, this.originalCount = 0;
|
super(), this.searchInput = null, this.itemCards = [], this.countElement = null, this.debounceTimer = null, this.originalCount = 0;
|
||||||
@@ -1046,23 +1114,23 @@ class Z extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
show(e, t, i, n = !1, s = 0, o = null, r = null, l = null) {
|
show(e, t, i, n = !1, s = 0, o = null, r = null, l = null) {
|
||||||
const c = this.querySelector("#single-page-image"), d = this.querySelector("#page-number"), u = this.querySelector("#page-icon");
|
const c = this.querySelector("#single-page-image"), h = this.querySelector("#page-number"), d = this.querySelector("#page-icon");
|
||||||
this.querySelector("#page-indicator"), c.src = e, c.alt = t, this.currentPageNumber = i, this.currentIsBeilage = n, this.currentPartNumber = o;
|
this.querySelector("#page-indicator"), c.src = e, c.alt = t, this.currentPageNumber = i, this.currentIsBeilage = n, this.currentPartNumber = o;
|
||||||
let h;
|
let u;
|
||||||
if (l)
|
if (l)
|
||||||
h = l;
|
u = l;
|
||||||
else {
|
else {
|
||||||
const b = this.getIssueContext(i);
|
const m = this.getIssueContext(i);
|
||||||
h = b ? `${b}, ${i}` : `${i}`;
|
u = m ? `${m}, ${i}` : `${i}`;
|
||||||
}
|
}
|
||||||
if (d.innerHTML = h, s && i === s) {
|
if (h.innerHTML = u, s && i === s) {
|
||||||
d.style.position = "relative";
|
h.style.position = "relative";
|
||||||
const b = d.querySelector(".target-page-dot");
|
const m = h.querySelector(".target-page-dot");
|
||||||
b && b.remove();
|
m && m.remove();
|
||||||
const g = document.createElement("span");
|
const g = document.createElement("span");
|
||||||
g.className = "target-page-dot absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full z-10", g.title = "verlinkte Seite", d.appendChild(g);
|
g.className = "target-page-dot absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full z-10", g.title = "verlinkte Seite", h.appendChild(g);
|
||||||
}
|
}
|
||||||
r ? r === "part-number" && o !== null ? u.innerHTML = `<span class="part-number bg-slate-100 text-slate-800 font-bold px-1.5 py-0.5 rounded border border-slate-400 flex items-center justify-center">${o}. Teil</span>` : u.innerHTML = this.generateIconFromType(r) : u.innerHTML = this.generateFallbackIcon(i, n, o), this.updateNavigationButtons(), this.style.display = "block", this.setAttribute("active", "true");
|
r ? r === "part-number" && o !== null ? d.innerHTML = `<span class="part-number bg-slate-100 text-slate-800 font-bold px-1.5 py-0.5 rounded border border-slate-400 flex items-center justify-center">${o}. Teil</span>` : d.innerHTML = this.generateIconFromType(r) : d.innerHTML = this.generateFallbackIcon(i, n, o), this.updateNavigationButtons(), this.style.display = "block", this.setAttribute("active", "true");
|
||||||
const p = this.querySelector(".flex-1.overflow-auto");
|
const p = this.querySelector(".flex-1.overflow-auto");
|
||||||
p && (p.scrollTop = 0), document.body.style.overflow = "hidden", document.dispatchEvent(
|
p && (p.scrollTop = 0), document.body.style.overflow = "hidden", document.dispatchEvent(
|
||||||
new CustomEvent("singlepageviewer:opened", {
|
new CustomEvent("singlepageviewer:opened", {
|
||||||
@@ -1190,10 +1258,10 @@ class Z extends HTMLElement {
|
|||||||
o = i.getAttribute("data-page-icon-type"), i.querySelector(".part-number") && (o = "part-number");
|
o = i.getAttribute("data-page-icon-type"), i.querySelector(".part-number") && (o = "part-number");
|
||||||
const c = i.querySelector(".page-indicator");
|
const c = i.querySelector(".page-indicator");
|
||||||
if (c) {
|
if (c) {
|
||||||
const d = c.cloneNode(!0);
|
const h = c.cloneNode(!0);
|
||||||
d.querySelectorAll("i").forEach((p) => p.remove()), d.querySelectorAll(
|
h.querySelectorAll("i").forEach((p) => p.remove()), h.querySelectorAll(
|
||||||
'[class*="target-page-dot"], .target-page-indicator'
|
'[class*="target-page-dot"], .target-page-indicator'
|
||||||
).forEach((p) => p.remove()), r = d.textContent.trim();
|
).forEach((p) => p.remove()), r = h.textContent.trim();
|
||||||
}
|
}
|
||||||
this.show(
|
this.show(
|
||||||
n.src,
|
n.src,
|
||||||
@@ -1247,12 +1315,12 @@ class Z extends HTMLElement {
|
|||||||
if (o) {
|
if (o) {
|
||||||
const c = o.querySelector(".page-indicator");
|
const c = o.querySelector(".page-indicator");
|
||||||
if (c) {
|
if (c) {
|
||||||
const d = c.textContent.trim(), u = d.match(/(\d{1,2}\.\d{1,2}\.\d{4}\s+Nr\.\s+\d+)/);
|
const h = c.textContent.trim(), d = h.match(/(\d{1,2}\.\d{1,2}\.\d{4}\s+Nr\.\s+\d+)/);
|
||||||
|
if (d)
|
||||||
|
return d[1];
|
||||||
|
const u = h.match(/(\d{4})\s+Nr\.\s+(\d+)/);
|
||||||
if (u)
|
if (u)
|
||||||
return u[1];
|
return `${u[1]} Nr. ${u[2]}`;
|
||||||
const h = d.match(/(\d{4})\s+Nr\.\s+(\d+)/);
|
|
||||||
if (h)
|
|
||||||
return `${h[1]} Nr. ${h[2]}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const l = document.title.match(/(\d{4}).*Nr\.\s*(\d+)/);
|
const l = document.title.match(/(\d{4}).*Nr\.\s*(\d+)/);
|
||||||
@@ -1281,7 +1349,7 @@ window.addEventListener("beforeunload", function() {
|
|||||||
const a = document.querySelector("single-page-viewer");
|
const a = document.querySelector("single-page-viewer");
|
||||||
a && a.close();
|
a && a.close();
|
||||||
});
|
});
|
||||||
class J extends HTMLElement {
|
class X extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.isVisible = !1, this.scrollHandler = null, this.htmxAfterSwapHandler = null;
|
super(), this.isVisible = !1, this.scrollHandler = null, this.htmxAfterSwapHandler = null;
|
||||||
}
|
}
|
||||||
@@ -1322,8 +1390,8 @@ class J extends HTMLElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("scroll-to-top-button", J);
|
customElements.define("scroll-to-top-button", X);
|
||||||
class X extends HTMLElement {
|
class J extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.pageObserver = null, this.pageContainers = /* @__PURE__ */ new Map(), this.singlePageViewerActive = !1, this.singlePageViewerCurrentPage = null, this.boundHandleSinglePageViewer = this.handleSinglePageViewer.bind(this);
|
super(), this.pageObserver = null, this.pageContainers = /* @__PURE__ */ new Map(), this.singlePageViewerActive = !1, this.singlePageViewerCurrentPage = null, this.boundHandleSinglePageViewer = this.handleSinglePageViewer.bind(this);
|
||||||
}
|
}
|
||||||
@@ -1408,7 +1476,7 @@ class X extends HTMLElement {
|
|||||||
}
|
}
|
||||||
const o = t.getBoundingClientRect(), r = e.getBoundingClientRect();
|
const o = t.getBoundingClientRect(), r = e.getBoundingClientRect();
|
||||||
if (!(r.top >= o.top && r.bottom <= o.bottom)) {
|
if (!(r.top >= o.top && r.bottom <= o.bottom)) {
|
||||||
const c = t.scrollTop, d = r.top - o.top + c, u = o.height, h = r.height, p = d - (u - h) / 2;
|
const c = t.scrollTop, h = r.top - o.top + c, d = o.height, u = r.height, p = h - (d - u) / 2;
|
||||||
t.scrollTo({
|
t.scrollTo({
|
||||||
top: Math.max(0, p),
|
top: Math.max(0, p),
|
||||||
behavior: "smooth"
|
behavior: "smooth"
|
||||||
@@ -1442,8 +1510,8 @@ class X extends HTMLElement {
|
|||||||
this.pageObserver && (this.pageObserver.disconnect(), this.pageObserver = null), document.removeEventListener("singlepageviewer:opened", this.boundHandleSinglePageViewer), document.removeEventListener("singlepageviewer:closed", this.boundHandleSinglePageViewer), document.removeEventListener("singlepageviewer:pagechanged", this.boundHandleSinglePageViewer), this.pageContainers.clear();
|
this.pageObserver && (this.pageObserver.disconnect(), this.pageObserver = null), document.removeEventListener("singlepageviewer:opened", this.boundHandleSinglePageViewer), document.removeEventListener("singlepageviewer:closed", this.boundHandleSinglePageViewer), document.removeEventListener("singlepageviewer:pagechanged", this.boundHandleSinglePageViewer), this.pageContainers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("inhaltsverzeichnis-scrollspy", X);
|
customElements.define("inhaltsverzeichnis-scrollspy", J);
|
||||||
class _ extends HTMLElement {
|
class G extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.innerHTML = `
|
super(), this.innerHTML = `
|
||||||
<div id="error-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center backdrop-blur-sm">
|
<div id="error-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center backdrop-blur-sm">
|
||||||
@@ -1491,30 +1559,30 @@ class _ extends HTMLElement {
|
|||||||
window.showErrorModal = (e) => this.show(e), window.closeErrorModal = () => this.close();
|
window.showErrorModal = (e) => this.show(e), window.closeErrorModal = () => this.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("error-modal", _);
|
customElements.define("error-modal", G);
|
||||||
window.currentPageContainers = window.currentPageContainers || [];
|
window.currentPageContainers = window.currentPageContainers || [];
|
||||||
window.currentActiveIndex = window.currentActiveIndex || 0;
|
window.currentActiveIndex = window.currentActiveIndex || 0;
|
||||||
window.pageObserver = window.pageObserver || null;
|
window.pageObserver = window.pageObserver || null;
|
||||||
function G(a, e, t, i = null) {
|
function U(a, e, t, i = null) {
|
||||||
let n = document.querySelector("single-page-viewer");
|
let n = document.querySelector("single-page-viewer");
|
||||||
n || (n = document.createElement("single-page-viewer"), document.body.appendChild(n));
|
n || (n = document.createElement("single-page-viewer"), document.body.appendChild(n));
|
||||||
const s = a.closest('[data-beilage="true"]') !== null, o = window.templateData && window.templateData.targetPage ? window.templateData.targetPage : 0, r = a.closest(".newspaper-page-container, .piece-page-container");
|
const s = a.closest('[data-beilage="true"]') !== null, o = window.templateData && window.templateData.targetPage ? window.templateData.targetPage : 0, r = a.closest(".newspaper-page-container, .piece-page-container");
|
||||||
let l = null, c = null;
|
let l = null, c = null;
|
||||||
if (r) {
|
if (r) {
|
||||||
l = r.getAttribute("data-page-icon-type"), r.querySelector(".part-number") && (l = "part-number");
|
l = r.getAttribute("data-page-icon-type"), r.querySelector(".part-number") && (l = "part-number");
|
||||||
const u = r.querySelector(".page-indicator");
|
const d = r.querySelector(".page-indicator");
|
||||||
if (u) {
|
if (d) {
|
||||||
const h = u.cloneNode(!0);
|
const u = d.cloneNode(!0);
|
||||||
h.querySelectorAll("i").forEach((g) => g.remove()), h.querySelectorAll('[class*="target-page-dot"], .target-page-indicator').forEach((g) => g.remove()), c = h.textContent.trim();
|
u.querySelectorAll("i").forEach((g) => g.remove()), u.querySelectorAll('[class*="target-page-dot"], .target-page-indicator').forEach((g) => g.remove()), c = u.textContent.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.show(a.src, a.alt, e, s, o, i, l, c);
|
n.show(a.src, a.alt, e, s, o, i, l, c);
|
||||||
}
|
}
|
||||||
function H() {
|
function M() {
|
||||||
document.getElementById("pageModal").classList.add("hidden");
|
document.getElementById("pageModal").classList.add("hidden");
|
||||||
}
|
}
|
||||||
function U() {
|
function Q() {
|
||||||
if (window.pageObserver && (window.pageObserver.disconnect(), window.pageObserver = null), window.currentPageContainers = Array.from(document.querySelectorAll(".newspaper-page-container")), window.currentActiveIndex = 0, S(), document.querySelector(".newspaper-page-container")) {
|
if (window.pageObserver && (window.pageObserver.disconnect(), window.pageObserver = null), window.currentPageContainers = Array.from(document.querySelectorAll(".newspaper-page-container")), window.currentActiveIndex = 0, C(), document.querySelector(".newspaper-page-container")) {
|
||||||
let e = /* @__PURE__ */ new Set();
|
let e = /* @__PURE__ */ new Set();
|
||||||
window.pageObserver = new IntersectionObserver(
|
window.pageObserver = new IntersectionObserver(
|
||||||
(t) => {
|
(t) => {
|
||||||
@@ -1523,7 +1591,7 @@ function U() {
|
|||||||
n !== -1 && (i.isIntersecting ? e.add(n) : e.delete(n));
|
n !== -1 && (i.isIntersecting ? e.add(n) : e.delete(n));
|
||||||
}), e.size > 0) {
|
}), e.size > 0) {
|
||||||
const n = Array.from(e).sort((s, o) => s - o)[0];
|
const n = Array.from(e).sort((s, o) => s - o)[0];
|
||||||
n !== window.currentActiveIndex && (window.currentActiveIndex = n, S());
|
n !== window.currentActiveIndex && (window.currentActiveIndex = n, C());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1534,13 +1602,13 @@ function U() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function Q() {
|
function ee() {
|
||||||
if (window.currentActiveIndex > 0) {
|
if (window.currentActiveIndex > 0) {
|
||||||
let a = -1;
|
let a = -1;
|
||||||
const e = [];
|
const e = [];
|
||||||
window.currentPageContainers.forEach((i, n) => {
|
window.currentPageContainers.forEach((i, n) => {
|
||||||
const s = i.getBoundingClientRect(), o = window.innerHeight, r = Math.max(s.top, 0), l = Math.min(s.bottom, o), c = Math.max(0, l - r), d = s.height;
|
const s = i.getBoundingClientRect(), o = window.innerHeight, r = Math.max(s.top, 0), l = Math.min(s.bottom, o), c = Math.max(0, l - r), h = s.height;
|
||||||
c / d >= 0.3 && e.push(n);
|
c / h >= 0.3 && e.push(n);
|
||||||
});
|
});
|
||||||
const t = Math.min(...e);
|
const t = Math.min(...e);
|
||||||
for (let i = t - 1; i >= 0; i--)
|
for (let i = t - 1; i >= 0; i--)
|
||||||
@@ -1551,17 +1619,17 @@ function Q() {
|
|||||||
a === -1 && t > 0 && (a = t - 1), a >= 0 && (window.currentActiveIndex = a, window.currentPageContainers[window.currentActiveIndex].scrollIntoView({
|
a === -1 && t > 0 && (a = t - 1), a >= 0 && (window.currentActiveIndex = a, window.currentPageContainers[window.currentActiveIndex].scrollIntoView({
|
||||||
block: "start"
|
block: "start"
|
||||||
}), setTimeout(() => {
|
}), setTimeout(() => {
|
||||||
S();
|
C();
|
||||||
}, 100));
|
}, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function ee() {
|
function te() {
|
||||||
if (window.currentActiveIndex < window.currentPageContainers.length - 1) {
|
if (window.currentActiveIndex < window.currentPageContainers.length - 1) {
|
||||||
let a = -1;
|
let a = -1;
|
||||||
const e = [];
|
const e = [];
|
||||||
window.currentPageContainers.forEach((i, n) => {
|
window.currentPageContainers.forEach((i, n) => {
|
||||||
const s = i.getBoundingClientRect(), o = window.innerHeight, r = Math.max(s.top, 0), l = Math.min(s.bottom, o), c = Math.max(0, l - r), d = s.height;
|
const s = i.getBoundingClientRect(), o = window.innerHeight, r = Math.max(s.top, 0), l = Math.min(s.bottom, o), c = Math.max(0, l - r), h = s.height;
|
||||||
c / d >= 0.3 && e.push(n);
|
c / h >= 0.3 && e.push(n);
|
||||||
});
|
});
|
||||||
const t = Math.max(...e);
|
const t = Math.max(...e);
|
||||||
for (let i = t + 1; i < window.currentPageContainers.length; i++)
|
for (let i = t + 1; i < window.currentPageContainers.length; i++)
|
||||||
@@ -1572,11 +1640,11 @@ function ee() {
|
|||||||
a === -1 && t < window.currentPageContainers.length - 1 && (a = t + 1), a >= 0 && a < window.currentPageContainers.length && (window.currentActiveIndex = a, window.currentPageContainers[window.currentActiveIndex].scrollIntoView({
|
a === -1 && t < window.currentPageContainers.length - 1 && (a = t + 1), a >= 0 && a < window.currentPageContainers.length && (window.currentActiveIndex = a, window.currentPageContainers[window.currentActiveIndex].scrollIntoView({
|
||||||
block: "start"
|
block: "start"
|
||||||
}), setTimeout(() => {
|
}), setTimeout(() => {
|
||||||
S();
|
C();
|
||||||
}, 100));
|
}, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function te() {
|
function ie() {
|
||||||
if (q()) {
|
if (q()) {
|
||||||
const e = document.querySelector("#newspaper-content .newspaper-page-container");
|
const e = document.querySelector("#newspaper-content .newspaper-page-container");
|
||||||
e && e.scrollIntoView({
|
e && e.scrollIntoView({
|
||||||
@@ -1609,14 +1677,14 @@ function q() {
|
|||||||
}
|
}
|
||||||
return !1;
|
return !1;
|
||||||
}
|
}
|
||||||
function S() {
|
function C() {
|
||||||
const a = document.getElementById("prevPageBtn"), e = document.getElementById("nextPageBtn"), t = document.getElementById("beilageBtn");
|
const a = document.getElementById("prevPageBtn"), e = document.getElementById("nextPageBtn"), t = document.getElementById("beilageBtn");
|
||||||
if (a && (a.style.display = "flex", window.currentActiveIndex <= 0 ? (a.disabled = !0, a.classList.add("opacity-50", "cursor-not-allowed"), a.classList.remove("hover:bg-gray-200")) : (a.disabled = !1, a.classList.remove("opacity-50", "cursor-not-allowed"), a.classList.add("hover:bg-gray-200"))), e && (e.style.display = "flex", window.currentActiveIndex >= window.currentPageContainers.length - 1 ? (e.disabled = !0, e.classList.add("opacity-50", "cursor-not-allowed"), e.classList.remove("hover:bg-gray-200")) : (e.disabled = !1, e.classList.remove("opacity-50", "cursor-not-allowed"), e.classList.add("hover:bg-gray-200"))), t) {
|
if (a && (a.style.display = "flex", window.currentActiveIndex <= 0 ? (a.disabled = !0, a.classList.add("opacity-50", "cursor-not-allowed"), a.classList.remove("hover:bg-gray-200")) : (a.disabled = !1, a.classList.remove("opacity-50", "cursor-not-allowed"), a.classList.add("hover:bg-gray-200"))), e && (e.style.display = "flex", window.currentActiveIndex >= window.currentPageContainers.length - 1 ? (e.disabled = !0, e.classList.add("opacity-50", "cursor-not-allowed"), e.classList.remove("hover:bg-gray-200")) : (e.disabled = !1, e.classList.remove("opacity-50", "cursor-not-allowed"), e.classList.add("hover:bg-gray-200"))), t) {
|
||||||
const i = q(), n = t.querySelector("i");
|
const i = q(), n = t.querySelector("i");
|
||||||
i ? (t.title = "Zur Hauptausgabe", t.className = "w-14 h-10 lg:w-16 lg:h-12 px-2 py-1 bg-gray-100 hover:bg-gray-200 text-gray-700 hover:text-gray-800 border border-gray-300 transition-colors duration-200 flex items-center justify-center cursor-pointer", n && (n.className = "ri-file-text-line text-lg lg:text-xl")) : (t.title = "Zu Beilage", t.className = "w-14 h-10 lg:w-16 lg:h-12 px-2 py-1 bg-amber-100 hover:bg-amber-200 text-amber-700 hover:text-amber-800 border border-amber-300 transition-colors duration-200 flex items-center justify-center cursor-pointer", n && (n.className = "ri-attachment-line text-lg lg:text-xl"));
|
i ? (t.title = "Zur Hauptausgabe", t.className = "w-14 h-10 lg:w-16 lg:h-12 px-2 py-1 bg-gray-100 hover:bg-gray-200 text-gray-700 hover:text-gray-800 border border-gray-300 transition-colors duration-200 flex items-center justify-center cursor-pointer", n && (n.className = "ri-file-text-line text-lg lg:text-xl")) : (t.title = "Zu Beilage", t.className = "w-14 h-10 lg:w-16 lg:h-12 px-2 py-1 bg-amber-100 hover:bg-amber-200 text-amber-700 hover:text-amber-800 border border-amber-300 transition-colors duration-200 flex items-center justify-center cursor-pointer", n && (n.className = "ri-attachment-line text-lg lg:text-xl"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function ie() {
|
function ne() {
|
||||||
const a = document.getElementById("shareLinkBtn");
|
const a = document.getElementById("shareLinkBtn");
|
||||||
let e = "";
|
let e = "";
|
||||||
if (window.currentActiveIndex !== void 0 && window.currentPageContainers && window.currentPageContainers[window.currentActiveIndex]) {
|
if (window.currentActiveIndex !== void 0 && window.currentPageContainers && window.currentPageContainers[window.currentActiveIndex]) {
|
||||||
@@ -1628,54 +1696,54 @@ function ie() {
|
|||||||
title: document.title,
|
title: document.title,
|
||||||
url: t
|
url: t
|
||||||
}).catch((i) => {
|
}).catch((i) => {
|
||||||
T(t, a);
|
I(t, a);
|
||||||
}) : T(t, a);
|
}) : I(t, a);
|
||||||
}
|
}
|
||||||
function T(a, e) {
|
function I(a, e) {
|
||||||
if (navigator.clipboard)
|
if (navigator.clipboard)
|
||||||
navigator.clipboard.writeText(a).then(() => {
|
navigator.clipboard.writeText(a).then(() => {
|
||||||
m(e, "Link kopiert!");
|
b(e, "Link kopiert!");
|
||||||
}).catch((t) => {
|
}).catch((t) => {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
});
|
});
|
||||||
else {
|
else {
|
||||||
const t = document.createElement("textarea");
|
const t = document.createElement("textarea");
|
||||||
t.value = a, document.body.appendChild(t), t.select();
|
t.value = a, document.body.appendChild(t), t.select();
|
||||||
try {
|
try {
|
||||||
const i = document.execCommand("copy");
|
const i = document.execCommand("copy");
|
||||||
m(e, i ? "Link kopiert!" : "Kopieren fehlgeschlagen");
|
b(e, i ? "Link kopiert!" : "Kopieren fehlgeschlagen");
|
||||||
} catch {
|
} catch {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
} finally {
|
} finally {
|
||||||
document.body.removeChild(t);
|
document.body.removeChild(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function ne() {
|
function se() {
|
||||||
const a = document.getElementById("citationBtn"), e = document.title || "KGPZ";
|
const a = document.getElementById("citationBtn"), e = document.title || "KGPZ";
|
||||||
let t = window.location.origin + window.location.pathname;
|
let t = window.location.origin + window.location.pathname;
|
||||||
t.includes("#") && (t = t.split("#")[0]);
|
t.includes("#") && (t = t.split("#")[0]);
|
||||||
const i = (/* @__PURE__ */ new Date()).toLocaleDateString("de-DE"), n = `Königsberger Gelehrte und Politische Zeitung (KGPZ). ${e}. Digital verfügbar unter: ${t} (Zugriff: ${i}).`;
|
const i = (/* @__PURE__ */ new Date()).toLocaleDateString("de-DE"), n = `Königsberger Gelehrte und Politische Zeitung (KGPZ). ${e}. Digital verfügbar unter: ${t} (Zugriff: ${i}).`;
|
||||||
if (navigator.clipboard)
|
if (navigator.clipboard)
|
||||||
navigator.clipboard.writeText(n).then(() => {
|
navigator.clipboard.writeText(n).then(() => {
|
||||||
m(a, "Zitation kopiert!");
|
b(a, "Zitation kopiert!");
|
||||||
}).catch((s) => {
|
}).catch((s) => {
|
||||||
m(a, "Kopieren fehlgeschlagen");
|
b(a, "Kopieren fehlgeschlagen");
|
||||||
});
|
});
|
||||||
else {
|
else {
|
||||||
const s = document.createElement("textarea");
|
const s = document.createElement("textarea");
|
||||||
s.value = n, document.body.appendChild(s), s.select();
|
s.value = n, document.body.appendChild(s), s.select();
|
||||||
try {
|
try {
|
||||||
const o = document.execCommand("copy");
|
const o = document.execCommand("copy");
|
||||||
m(a, o ? "Zitation kopiert!" : "Kopieren fehlgeschlagen");
|
b(a, o ? "Zitation kopiert!" : "Kopieren fehlgeschlagen");
|
||||||
} catch {
|
} catch {
|
||||||
m(a, "Kopieren fehlgeschlagen");
|
b(a, "Kopieren fehlgeschlagen");
|
||||||
} finally {
|
} finally {
|
||||||
document.body.removeChild(s);
|
document.body.removeChild(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function m(a, e) {
|
function b(a, e) {
|
||||||
const t = document.querySelector(".simple-popup");
|
const t = document.querySelector(".simple-popup");
|
||||||
t && t.remove();
|
t && t.remove();
|
||||||
const i = document.createElement("div");
|
const i = document.createElement("div");
|
||||||
@@ -1695,8 +1763,8 @@ function m(a, e) {
|
|||||||
`;
|
`;
|
||||||
const n = a.getBoundingClientRect(), s = window.innerHeight, o = window.innerWidth;
|
const n = a.getBoundingClientRect(), s = window.innerHeight, o = window.innerWidth;
|
||||||
let r = n.left - 10, l = n.bottom + 8;
|
let r = n.left - 10, l = n.bottom + 8;
|
||||||
const c = 120, d = 32;
|
const c = 120, h = 32;
|
||||||
r + c > o && (r = n.right - c + 10), l + d > s && (l = n.top - d - 8), i.style.left = Math.max(5, r) + "px", i.style.top = Math.max(5, l) + "px", document.body.appendChild(i), setTimeout(() => {
|
r + c > o && (r = n.right - c + 10), l + h > s && (l = n.top - h - 8), i.style.left = Math.max(5, r) + "px", i.style.top = Math.max(5, l) + "px", document.body.appendChild(i), setTimeout(() => {
|
||||||
i.style.opacity = "1";
|
i.style.opacity = "1";
|
||||||
}, 10), setTimeout(() => {
|
}, 10), setTimeout(() => {
|
||||||
i.style.opacity = "0", setTimeout(() => {
|
i.style.opacity = "0", setTimeout(() => {
|
||||||
@@ -1704,7 +1772,7 @@ function m(a, e) {
|
|||||||
}, 200);
|
}, 200);
|
||||||
}, 2e3);
|
}, 2e3);
|
||||||
}
|
}
|
||||||
function se(a, e, t = !1) {
|
function oe(a, e, t = !1) {
|
||||||
let i = "";
|
let i = "";
|
||||||
if (t)
|
if (t)
|
||||||
i = window.location.origin + window.location.pathname + `#beilage-1-page-${a}`;
|
i = window.location.origin + window.location.pathname + `#beilage-1-page-${a}`;
|
||||||
@@ -1719,24 +1787,24 @@ function se(a, e, t = !1) {
|
|||||||
const n = i;
|
const n = i;
|
||||||
if (navigator.clipboard)
|
if (navigator.clipboard)
|
||||||
navigator.clipboard.writeText(n).then(() => {
|
navigator.clipboard.writeText(n).then(() => {
|
||||||
m(e, "Link kopiert!");
|
b(e, "Link kopiert!");
|
||||||
}).catch((s) => {
|
}).catch((s) => {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
});
|
});
|
||||||
else {
|
else {
|
||||||
const s = document.createElement("textarea");
|
const s = document.createElement("textarea");
|
||||||
s.value = n, document.body.appendChild(s), s.select();
|
s.value = n, document.body.appendChild(s), s.select();
|
||||||
try {
|
try {
|
||||||
const o = document.execCommand("copy");
|
const o = document.execCommand("copy");
|
||||||
m(e, o ? "Link kopiert!" : "Kopieren fehlgeschlagen");
|
b(e, o ? "Link kopiert!" : "Kopieren fehlgeschlagen");
|
||||||
} catch {
|
} catch {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
} finally {
|
} finally {
|
||||||
document.body.removeChild(s);
|
document.body.removeChild(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function oe(a, e) {
|
function re(a, e) {
|
||||||
const t = document.title || "KGPZ", i = window.location.pathname.split("/");
|
const t = document.title || "KGPZ", i = window.location.pathname.split("/");
|
||||||
let n;
|
let n;
|
||||||
if (i.length >= 3) {
|
if (i.length >= 3) {
|
||||||
@@ -1747,33 +1815,33 @@ function oe(a, e) {
|
|||||||
const s = n, o = (/* @__PURE__ */ new Date()).toLocaleDateString("de-DE"), r = `Königsberger Gelehrte und Politische Zeitung (KGPZ). ${t}, Seite ${a}. Digital verfügbar unter: ${s} (Zugriff: ${o}).`;
|
const s = n, o = (/* @__PURE__ */ new Date()).toLocaleDateString("de-DE"), r = `Königsberger Gelehrte und Politische Zeitung (KGPZ). ${t}, Seite ${a}. Digital verfügbar unter: ${s} (Zugriff: ${o}).`;
|
||||||
if (navigator.clipboard)
|
if (navigator.clipboard)
|
||||||
navigator.clipboard.writeText(r).then(() => {
|
navigator.clipboard.writeText(r).then(() => {
|
||||||
m(e, "Zitation kopiert!");
|
b(e, "Zitation kopiert!");
|
||||||
}).catch((l) => {
|
}).catch((l) => {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
});
|
});
|
||||||
else {
|
else {
|
||||||
const l = document.createElement("textarea");
|
const l = document.createElement("textarea");
|
||||||
l.value = r, document.body.appendChild(l), l.select();
|
l.value = r, document.body.appendChild(l), l.select();
|
||||||
try {
|
try {
|
||||||
const c = document.execCommand("copy");
|
const c = document.execCommand("copy");
|
||||||
m(e, c ? "Zitation kopiert!" : "Kopieren fehlgeschlagen");
|
b(e, c ? "Zitation kopiert!" : "Kopieren fehlgeschlagen");
|
||||||
} catch {
|
} catch {
|
||||||
m(e, "Kopieren fehlgeschlagen");
|
b(e, "Kopieren fehlgeschlagen");
|
||||||
} finally {
|
} finally {
|
||||||
document.body.removeChild(l);
|
document.body.removeChild(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function M() {
|
function A() {
|
||||||
U(), window.addEventListener("scroll", function() {
|
Q(), window.addEventListener("scroll", function() {
|
||||||
clearTimeout(window.scrollTimeout), window.scrollTimeout = setTimeout(() => {
|
clearTimeout(window.scrollTimeout), window.scrollTimeout = setTimeout(() => {
|
||||||
S();
|
C();
|
||||||
}, 50);
|
}, 50);
|
||||||
}), document.addEventListener("keydown", function(a) {
|
}), document.addEventListener("keydown", function(a) {
|
||||||
a.key === "Escape" && H();
|
a.key === "Escape" && M();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function A() {
|
function B() {
|
||||||
const a = window.location.pathname;
|
const a = window.location.pathname;
|
||||||
document.querySelectorAll(".citation-link[data-citation-url]").forEach((t) => {
|
document.querySelectorAll(".citation-link[data-citation-url]").forEach((t) => {
|
||||||
const i = t.getAttribute("data-citation-url");
|
const i = t.getAttribute("data-citation-url");
|
||||||
@@ -1783,14 +1851,14 @@ function A() {
|
|||||||
else {
|
else {
|
||||||
const s = a.match(/^\/(\d{4})\/(\d+)(?:\/(\d+))?$/), o = i.match(/^\/(\d{4})\/(\d+)$/);
|
const s = a.match(/^\/(\d{4})\/(\d+)(?:\/(\d+))?$/), o = i.match(/^\/(\d{4})\/(\d+)$/);
|
||||||
if (s && o) {
|
if (s && o) {
|
||||||
const [, r, l, c] = s, [, d, u] = o;
|
const [, r, l, c] = s, [, h, d] = o;
|
||||||
r === d && l === u && (n = !0);
|
r === h && l === d && (n = !0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n ? (t.classList.add("text-red-700", "pointer-events-none"), t.setAttribute("aria-current", "page")) : (t.classList.remove("text-red-700", "pointer-events-none"), t.removeAttribute("aria-current"));
|
n ? (t.classList.add("text-red-700", "pointer-events-none"), t.setAttribute("aria-current", "page")) : (t.classList.remove("text-red-700", "pointer-events-none"), t.removeAttribute("aria-current"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function B() {
|
function N() {
|
||||||
const a = window.location.pathname, e = document.body;
|
const a = window.location.pathname, e = document.body;
|
||||||
e.classList.remove(
|
e.classList.remove(
|
||||||
"page-akteure",
|
"page-akteure",
|
||||||
@@ -1802,21 +1870,21 @@ function B() {
|
|||||||
"page-edition"
|
"page-edition"
|
||||||
), a.includes("/akteure/") || a.includes("/autoren") ? e.classList.add("page-akteure") : a.match(/\/\d{4}\/\d+/) ? e.classList.add("page-ausgabe") : a.includes("/search") || a.includes("/suche") ? e.classList.add("page-search") : a.includes("/ort/") ? e.classList.add("page-ort") : a.includes("/kategorie/") ? e.classList.add("page-kategorie") : a.includes("/beitrag/") ? e.classList.add("page-piece") : a.includes("/edition") && e.classList.add("page-edition");
|
), a.includes("/akteure/") || a.includes("/autoren") ? e.classList.add("page-akteure") : a.match(/\/\d{4}\/\d+/) ? e.classList.add("page-ausgabe") : a.includes("/search") || a.includes("/suche") ? e.classList.add("page-search") : a.includes("/ort/") ? e.classList.add("page-ort") : a.includes("/kategorie/") ? e.classList.add("page-kategorie") : a.includes("/beitrag/") ? e.classList.add("page-piece") : a.includes("/edition") && e.classList.add("page-edition");
|
||||||
}
|
}
|
||||||
window.enlargePage = G;
|
window.enlargePage = U;
|
||||||
window.closeModal = H;
|
window.closeModal = M;
|
||||||
window.scrollToPreviousPage = Q;
|
window.scrollToPreviousPage = ee;
|
||||||
window.scrollToNextPage = ee;
|
window.scrollToNextPage = te;
|
||||||
window.scrollToBeilage = te;
|
window.scrollToBeilage = ie;
|
||||||
window.shareCurrentPage = ie;
|
window.shareCurrentPage = ne;
|
||||||
window.generateCitation = ne;
|
window.generateCitation = se;
|
||||||
window.copyPagePermalink = se;
|
window.copyPagePermalink = oe;
|
||||||
window.generatePageCitation = oe;
|
window.generatePageCitation = re;
|
||||||
|
N();
|
||||||
B();
|
B();
|
||||||
A();
|
document.querySelector(".newspaper-page-container") && A();
|
||||||
document.querySelector(".newspaper-page-container") && M();
|
let ae = function(a) {
|
||||||
let re = function(a) {
|
N(), B(), H(), setTimeout(() => {
|
||||||
B(), A(), I(), setTimeout(() => {
|
document.querySelector(".newspaper-page-container") && A();
|
||||||
document.querySelector(".newspaper-page-container") && M();
|
|
||||||
}, 50);
|
}, 50);
|
||||||
};
|
};
|
||||||
document.body.addEventListener("htmx:afterSettle", re);
|
document.body.addEventListener("htmx:afterSettle", ae);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -71,70 +71,66 @@
|
|||||||
|
|
||||||
{{- /* Pieces List */ -}}
|
{{- /* Pieces List */ -}}
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-semibold text-slate-800 mb-4">
|
<h2 class="font-bold mb-4">
|
||||||
<i class="ri-newspaper-line mr-2"></i><u class="decoration underline-offset-3">Beiträge</u> ({{ .model.PieceCount }})
|
<i class="ri-newspaper-line mr-2"></i><u class="decoration underline-offset-3">Beiträge</u> ({{ .model.PieceCount }})
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{- if .model.Pieces -}}
|
{{- if .model.Pieces -}}
|
||||||
<div class="space-y-6 max-w-[85ch]">
|
<div class="columns-2 gap-6 hyphens-auto">
|
||||||
<div>
|
<h3 class="font-bold font-serif text-slate-800 mb-1 break-inside-avoid">{{ .model.Year }}</h3>
|
||||||
<h3 class="text-lg font-bold font-serif text-slate-800 mb-3">{{ .model.Year }}</h3>
|
|
||||||
|
|
||||||
<div class="space-y-1">
|
{{- /* Group pieces by title within the year */ -}}
|
||||||
{{- /* Group pieces by title within the year */ -}}
|
{{- $groupedPieces := dict -}}
|
||||||
{{- $groupedPieces := dict -}}
|
{{- range $_, $p := .model.Pieces -}}
|
||||||
{{- range $_, $p := .model.Pieces -}}
|
{{- $groupKey := "" -}}
|
||||||
{{- $groupKey := "" -}}
|
{{- if $p.Title -}}
|
||||||
{{- if $p.Title -}}
|
{{- $groupKey = index $p.Title 0 -}}
|
||||||
{{- $groupKey = index $p.Title 0 -}}
|
{{- else if $p.Incipit -}}
|
||||||
{{- else if $p.Incipit -}}
|
{{- $groupKey = index $p.Incipit 0 -}}
|
||||||
{{- $groupKey = index $p.Incipit 0 -}}
|
{{- else -}}
|
||||||
{{- else -}}
|
{{- $groupKey = printf "untitled-%s" $p.ID -}}
|
||||||
{{- $groupKey = printf "untitled-%s" $p.ID -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- $existing := index $groupedPieces $groupKey -}}
|
{{- $existing := index $groupedPieces $groupKey -}}
|
||||||
{{- if $existing -}}
|
{{- if $existing -}}
|
||||||
{{- $groupedPieces = merge $groupedPieces (dict $groupKey (append $existing $p)) -}}
|
{{- $groupedPieces = merge $groupedPieces (dict $groupKey (append $existing $p)) -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- $groupedPieces = merge $groupedPieces (dict $groupKey (slice $p)) -}}
|
{{- $groupedPieces = merge $groupedPieces (dict $groupKey (slice $p)) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- range $groupKey, $groupedItems := $groupedPieces -}}
|
{{- range $groupKey, $groupedItems := $groupedPieces -}}
|
||||||
<div>
|
<div class="break-inside-avoid mb-1">
|
||||||
<div class="pb-1 text-lg indent-4">
|
<div class="pb-1 indent-4">
|
||||||
{{- /* Use first piece for display text with colon format for places */ -}}
|
{{- /* Use first piece for display text with colon format for places */ -}}
|
||||||
{{ template "_unified_piece_entry" (dict "Piece" (index $groupedItems 0) "CurrentActorID" "" "DisplayMode" "place" "ShowPlaceTags" false "UseColonFormat" true "ShowContinuation" false) }}
|
{{ template "_unified_piece_entry" (dict "Piece" (index $groupedItems 0) "CurrentActorID" "" "DisplayMode" "place" "ShowPlaceTags" false "UseColonFormat" true "ShowContinuation" false) }}
|
||||||
|
|
||||||
{{- /* Show all citations from all pieces in this group inline with commas */ -}}
|
{{- /* Show all citations from all pieces in this group inline with commas */ -}}
|
||||||
{{ " " }}{{- range $groupIndex, $groupItem := $groupedItems -}}
|
{{ " " }}{{- range $groupIndex, $groupItem := $groupedItems -}}
|
||||||
{{- range $issueIndex, $issue := $groupItem.IssueRefs -}}
|
{{- range $issueIndex, $issue := $groupItem.IssueRefs -}}
|
||||||
{{- /* Only show citations for the current year */ -}}
|
{{- /* Only show citations for the current year */ -}}
|
||||||
{{- if eq $issue.When.Year $.model.Year -}}
|
{{- if eq $issue.When.Year $.model.Year -}}
|
||||||
{{- if or (gt $groupIndex 0) (gt $issueIndex 0) }}, {{ end -}}
|
{{- if or (gt $groupIndex 0) (gt $issueIndex 0) }}, {{ end -}}
|
||||||
<span class="text-blue-600 hover:text-blue-700 underline decoration-dotted hover:decoration-solid [&>a]:text-blue-600 [&>a:hover]:text-blue-700">{{- template "_citation" $issue -}}</span>
|
<span class="text-blue-600 hover:text-blue-700 underline decoration-dotted hover:decoration-solid [&>a]:text-blue-600 [&>a:hover]:text-blue-700">{{- template "_citation" $issue -}}</span>
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
{{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}}
|
{{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}}
|
||||||
{{- $firstGroupItem := index $groupedItems 0 -}}
|
{{- $firstGroupItem := index $groupedItems 0 -}}
|
||||||
{{- if gt (len $firstGroupItem.IssueRefs) 1 -}}
|
{{- if gt (len $firstGroupItem.IssueRefs) 1 -}}
|
||||||
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50
|
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50
|
||||||
hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200
|
hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200
|
||||||
hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
<i class="ri-file-copy-2-line text-xs"></i>
|
||||||
<a href="{{ GetPieceURL $firstGroupItem.ID }}" class="">
|
<a href="{{ GetPieceURL $firstGroupItem.ID }}" class="">
|
||||||
Ganzer Beitrag
|
Ganzer Beitrag
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
{{- end }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{- end }}
|
||||||
{{- end -}}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
<div class="bg-slate-50 rounded-lg p-8 text-center">
|
<div class="bg-slate-50 rounded-lg p-8 text-center">
|
||||||
|
|||||||
@@ -1,8 +1,24 @@
|
|||||||
<!-- Single Place Detail View -->
|
<!-- Single Place Detail View -->
|
||||||
<div class="max-w-7xl mx-auto px-8 py-8">
|
<div class="grid grid-cols-1 lg:grid-cols-7 gap-8">
|
||||||
<div class="bg-white px-6 py-6 rounded w-full lg:min-w-[800px] xl:min-w-[900px]">
|
{{- /* Main content - Place details */ -}}
|
||||||
{{ template "_back_navigation" . }}
|
<div class="lg:col-span-5 pt-4">
|
||||||
{{ template "_place_header" .model.SelectedPlace }}
|
<div class="bg-white px-6 py-6 rounded w-full">
|
||||||
{{ template "_place_pieces" .model.SelectedPlace }}
|
{{ template "_back_navigation" . }}
|
||||||
|
{{ template "_place_header" .model.SelectedPlace }}
|
||||||
|
{{ template "_place_pieces" .model.SelectedPlace }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{- /* Sidebar - Map */ -}}
|
||||||
|
<div class="lg:col-span-2 sticky top-0 self-start">
|
||||||
|
<div class="bg-white rounded">
|
||||||
|
{{ if .model.SelectedPlace.Place.Geo }}
|
||||||
|
{{ $geonames := GetGeonames .model.SelectedPlace.Place.Geo }}
|
||||||
|
{{ if and $geonames $geonames.Lat $geonames.Lng }}
|
||||||
|
{{ $placeJSON := printf `{"id":"%s","name":"%s","toponymName":"%s","lat":"%s","lng":"%s"}` .model.SelectedPlace.Place.ID (index .model.SelectedPlace.Place.Names 0) $geonames.Name $geonames.Lat $geonames.Lng }}
|
||||||
|
<places-map-single data-place="{{ $placeJSON }}" class="w-full"></places-map-single>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -596,10 +596,10 @@ export class PlacesMap extends HTMLElement {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Trigger when element enters viewport
|
// Trigger when any part enters viewport - better for small elements
|
||||||
threshold: 0.1,
|
threshold: 0,
|
||||||
// No root margin for precise detection
|
// Add some margin to trigger slightly before/after entering viewport
|
||||||
rootMargin: "0px",
|
rootMargin: "10px 0px",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -608,20 +608,6 @@ export class PlacesMap extends HTMLElement {
|
|||||||
this.intersectionObserver.observe(container);
|
this.intersectionObserver.observe(container);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Force an immediate check by triggering a scroll event
|
|
||||||
setTimeout(() => {
|
|
||||||
// Manually trigger intersection calculation
|
|
||||||
placeContainers.forEach((container) => {
|
|
||||||
const rect = container.getBoundingClientRect();
|
|
||||||
const isVisible = rect.top < window.innerHeight && rect.bottom > 0;
|
|
||||||
const placeId = container.getAttribute("data-place-id");
|
|
||||||
const mapPoint = this.mapPoints.get(placeId);
|
|
||||||
|
|
||||||
if (mapPoint && isVisible) {
|
|
||||||
this.setPointActive(mapPoint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPointActive(point) {
|
setPointActive(point) {
|
||||||
@@ -646,6 +632,7 @@ export class PlacesMap extends HTMLElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.tooltip && tooltipText) {
|
if (this.tooltip && tooltipText) {
|
||||||
// Set tooltip content and position
|
// Set tooltip content and position
|
||||||
this.tooltip.textContent = tooltipText;
|
this.tooltip.textContent = tooltipText;
|
||||||
@@ -784,63 +771,18 @@ export class PlacesMap extends HTMLElement {
|
|||||||
// Track the currently hovered place ID
|
// Track the currently hovered place ID
|
||||||
this.currentHoveredPlaceId = placeId;
|
this.currentHoveredPlaceId = placeId;
|
||||||
|
|
||||||
// Give the point a subtle highlight by making it larger immediately
|
// Give the point a more visible highlight by making it larger immediately
|
||||||
mapPoint.classList.remove("w-1", "h-1", "w-1.5", "h-1.5");
|
mapPoint.classList.remove("w-1", "h-1", "w-1.5", "h-1.5");
|
||||||
mapPoint.classList.add("w-2", "h-2");
|
mapPoint.classList.add("w-2.5", "h-2.5");
|
||||||
mapPoint.style.zIndex = "25";
|
mapPoint.style.zIndex = "25";
|
||||||
|
|
||||||
// Don't show NEW tooltip if scrolling blocked (behavior 4)
|
// No tooltip when hovering over place titles - only visual feedback
|
||||||
if (this.isNewPopupBlocked(placeId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltipText = mapPoint.dataset.tooltipText;
|
|
||||||
if (this.tooltip && tooltipText) {
|
|
||||||
// Set tooltip content and position
|
|
||||||
this.tooltip.textContent = tooltipText;
|
|
||||||
|
|
||||||
// Position tooltip at the map point location
|
|
||||||
const pointRect = mapPoint.getBoundingClientRect();
|
|
||||||
const mapRect = this.mapElement.getBoundingClientRect();
|
|
||||||
const x = pointRect.left - mapRect.left + pointRect.width / 2;
|
|
||||||
const y = pointRect.top - mapRect.top + pointRect.height / 2;
|
|
||||||
|
|
||||||
this.tooltip.style.left = `${x}px`;
|
|
||||||
this.tooltip.style.top = `${y}px`;
|
|
||||||
|
|
||||||
// Clear any existing timeouts
|
|
||||||
this.clearTimeouts();
|
|
||||||
|
|
||||||
if (this.isTooltipVisible) {
|
|
||||||
// Behavior 2b: Popup was visible -- instant popup
|
|
||||||
this.tooltip.classList.remove("opacity-0");
|
|
||||||
this.tooltip.classList.add("opacity-100");
|
|
||||||
} else {
|
|
||||||
// Behavior 2a: No popup was visible -- Popup after 150ms
|
|
||||||
this.showTimeout = setTimeout(() => {
|
|
||||||
this.tooltip.classList.remove("opacity-0");
|
|
||||||
this.tooltip.classList.add("opacity-100");
|
|
||||||
this.isTooltipVisible = true;
|
|
||||||
}, 150);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (action === "hide") {
|
} else if (action === "hide") {
|
||||||
// Clear the currently hovered place ID
|
// Clear the currently hovered place ID
|
||||||
this.currentHoveredPlaceId = "";
|
this.currentHoveredPlaceId = "";
|
||||||
|
|
||||||
// Behavior 3: Leave tile or map point -- close after 150ms delay
|
|
||||||
// NOTE: This is NOT blocked during scroll - existing popup should close when mouse leaves
|
|
||||||
this.clearTimeouts();
|
|
||||||
this.hideTimeout = setTimeout(() => {
|
|
||||||
if (this.tooltip) {
|
|
||||||
this.tooltip.classList.remove("opacity-100");
|
|
||||||
this.tooltip.classList.add("opacity-0");
|
|
||||||
this.isTooltipVisible = false;
|
|
||||||
}
|
|
||||||
}, 150);
|
|
||||||
|
|
||||||
// Remove point highlight - restore original size based on current state
|
// Remove point highlight - restore original size based on current state
|
||||||
mapPoint.classList.remove("w-2", "h-2");
|
mapPoint.classList.remove("w-2.5", "h-2.5");
|
||||||
// Check if this point is currently active or inactive
|
// Check if this point is currently active or inactive
|
||||||
if (mapPoint.className.includes("bg-red-500")) {
|
if (mapPoint.className.includes("bg-red-500")) {
|
||||||
// Active point
|
// Active point
|
||||||
@@ -872,7 +814,229 @@ export class PlacesMap extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places Map Single Web Component
|
||||||
|
* Embeds an SVG map with a single highlighted place
|
||||||
|
*/
|
||||||
|
export class PlacesMapSingle extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.place = null;
|
||||||
|
this.mapElement = null;
|
||||||
|
this.pointsContainer = null;
|
||||||
|
this.tooltip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.parseData();
|
||||||
|
this.render();
|
||||||
|
this.initializeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
parseData() {
|
||||||
|
try {
|
||||||
|
const placeData = this.dataset.place;
|
||||||
|
if (placeData) {
|
||||||
|
this.place = JSON.parse(placeData);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to parse place data:", error);
|
||||||
|
this.place = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.innerHTML = `
|
||||||
|
<div class="map-container relative w-full aspect-[5/7] overflow-hidden bg-slate-100">
|
||||||
|
<div class="transform-wrapper absolute top-0 left-0 w-full h-auto origin-top-left">
|
||||||
|
<img src="/assets/Europe.svg" alt="Map of Europe" class="block w-full h-auto">
|
||||||
|
<div class="points-container absolute top-0 left-0 w-full h-full"></div>
|
||||||
|
</div>
|
||||||
|
<div class="absolute bottom-0 right-0 h-auto text-[0.6rem] bg-white px-0.5 bg-opacity-[0.5] border">
|
||||||
|
<i class="ri-creative-commons-line"></i>
|
||||||
|
<a href="https://commons.wikimedia.org/wiki/File:Europe_laea_topography.svg" target="_blank" class="">
|
||||||
|
Wikimedia Commons
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Tooltip -->
|
||||||
|
<div class="map-tooltip absolute bg-slate-800 text-white text-sm px-2 py-1 rounded shadow-lg pointer-events-none opacity-0 transition-opacity duration-200 z-30 whitespace-nowrap" style="transform: translate(-50%, -100%); margin-top: -8px;"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.mapElement = this.querySelector(".map-container");
|
||||||
|
this.pointsContainer = this.querySelector(".points-container");
|
||||||
|
this.tooltip = this.querySelector(".map-tooltip");
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeMap() {
|
||||||
|
if (!this.place || !this.place.lat || !this.place.lng || !this.pointsContainer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map extent constants
|
||||||
|
const MAP_EXTENT_METERS = { xmin: 2555000, ymin: 1350000, xmax: 7405000, ymax: 5500000 };
|
||||||
|
const PROJECTION_CENTER = { lon: 10, lat: 52 };
|
||||||
|
|
||||||
|
// Convert lat/lng to % calculation
|
||||||
|
const convertLatLngToPercent = (lat, lng) => {
|
||||||
|
const R = 6371000;
|
||||||
|
const FE = 4321000;
|
||||||
|
const FN = 3210000;
|
||||||
|
const lon_0_rad = (PROJECTION_CENTER.lon * Math.PI) / 180;
|
||||||
|
const lat_0_rad = (PROJECTION_CENTER.lat * Math.PI) / 180;
|
||||||
|
const lon_rad = (lng * Math.PI) / 180;
|
||||||
|
const lat_rad = (lat * Math.PI) / 180;
|
||||||
|
const k_prime = Math.sqrt(
|
||||||
|
2 /
|
||||||
|
(1 +
|
||||||
|
Math.sin(lat_0_rad) * Math.sin(lat_rad) +
|
||||||
|
Math.cos(lat_0_rad) * Math.cos(lat_rad) * Math.cos(lon_rad - lon_0_rad)),
|
||||||
|
);
|
||||||
|
const x_proj = R * k_prime * Math.cos(lat_rad) * Math.sin(lon_rad - lon_0_rad);
|
||||||
|
const y_proj =
|
||||||
|
R *
|
||||||
|
k_prime *
|
||||||
|
(Math.cos(lat_0_rad) * Math.sin(lat_rad) -
|
||||||
|
Math.sin(lat_0_rad) * Math.cos(lat_rad) * Math.cos(lon_rad - lon_0_rad));
|
||||||
|
const finalX = x_proj + FE;
|
||||||
|
const finalY = y_proj + FN;
|
||||||
|
const mapWidthMeters = MAP_EXTENT_METERS.xmax - MAP_EXTENT_METERS.xmin;
|
||||||
|
const mapHeightMeters = MAP_EXTENT_METERS.ymax - MAP_EXTENT_METERS.ymin;
|
||||||
|
const xPercent = ((finalX - MAP_EXTENT_METERS.xmin) / mapWidthMeters) * 100;
|
||||||
|
const yPercent = ((MAP_EXTENT_METERS.ymax - finalY) / mapHeightMeters) * 100;
|
||||||
|
return { x: xPercent, y: yPercent };
|
||||||
|
};
|
||||||
|
|
||||||
|
const lat = parseFloat(this.place.lat);
|
||||||
|
const lng = parseFloat(this.place.lng);
|
||||||
|
const position = convertLatLngToPercent(lat, lng);
|
||||||
|
|
||||||
|
// Only add point if it's within the visible map area
|
||||||
|
if (position.x >= 0 && position.x <= 100 && position.y >= 0 && position.y <= 100) {
|
||||||
|
const point = document.createElement("div");
|
||||||
|
point.style.left = `${position.x}%`;
|
||||||
|
point.style.top = `${position.y}%`;
|
||||||
|
point.style.transformOrigin = "center";
|
||||||
|
|
||||||
|
// Single highlighted point - moderately sized for zoomed view
|
||||||
|
point.className = "absolute w-2 h-2 bg-red-500 border border-red-700 rounded-full shadow-md -translate-x-1/2 -translate-y-1/2 z-20";
|
||||||
|
|
||||||
|
const tooltipText = `${this.place.name}${this.place.toponymName && this.place.toponymName !== this.place.name ? ` (${this.place.toponymName})` : ""}`;
|
||||||
|
point.dataset.tooltipText = tooltipText;
|
||||||
|
|
||||||
|
// Add hover event listeners
|
||||||
|
point.addEventListener("mouseenter", (e) => this.showTooltip(e));
|
||||||
|
point.addEventListener("mouseleave", () => this.hideTooltip());
|
||||||
|
point.addEventListener("mousemove", (e) => this.updateTooltipPosition(e));
|
||||||
|
|
||||||
|
this.pointsContainer.appendChild(point);
|
||||||
|
|
||||||
|
// Auto-zoom to the single point with some padding
|
||||||
|
this.autoZoomToPoint(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoZoomToPoint(position) {
|
||||||
|
// Create a balanced area around the point for zooming
|
||||||
|
const PADDING = 20; // 20% padding around the point
|
||||||
|
let minX = Math.max(0, position.x - PADDING);
|
||||||
|
let maxX = Math.min(100, position.x + PADDING);
|
||||||
|
let minY = Math.max(0, position.y - PADDING);
|
||||||
|
let maxY = Math.min(100, position.y + PADDING);
|
||||||
|
|
||||||
|
let width = maxX - minX;
|
||||||
|
let height = maxY - minY;
|
||||||
|
|
||||||
|
// Maintain 5:7 aspect ratio
|
||||||
|
const ASPECT_RATIO = 5 / 7;
|
||||||
|
const pointsAspectRatio = width / height;
|
||||||
|
|
||||||
|
let finalViewBox = { x: minX, y: minY, width: width, height: height };
|
||||||
|
|
||||||
|
if (pointsAspectRatio > ASPECT_RATIO) {
|
||||||
|
const newTargetHeight = width / ASPECT_RATIO;
|
||||||
|
finalViewBox.y = minY - (newTargetHeight - height) / 2;
|
||||||
|
finalViewBox.height = newTargetHeight;
|
||||||
|
} else {
|
||||||
|
const newTargetWidth = height * ASPECT_RATIO;
|
||||||
|
finalViewBox.x = minX - (newTargetWidth - width) / 2;
|
||||||
|
finalViewBox.width = newTargetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the final viewbox stays within map boundaries (0-100%)
|
||||||
|
if (finalViewBox.x < 0) {
|
||||||
|
finalViewBox.width += finalViewBox.x;
|
||||||
|
finalViewBox.x = 0;
|
||||||
|
}
|
||||||
|
if (finalViewBox.y < 0) {
|
||||||
|
finalViewBox.height += finalViewBox.y;
|
||||||
|
finalViewBox.y = 0;
|
||||||
|
}
|
||||||
|
if (finalViewBox.x + finalViewBox.width > 100) {
|
||||||
|
finalViewBox.width = 100 - finalViewBox.x;
|
||||||
|
}
|
||||||
|
if (finalViewBox.y + finalViewBox.height > 100) {
|
||||||
|
finalViewBox.height = 100 - finalViewBox.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure minimum zoom level - don't zoom in too much if constrained by boundaries
|
||||||
|
const MIN_VIEWPORT_SIZE = 30; // Minimum 30% of map should be visible
|
||||||
|
if (finalViewBox.width < MIN_VIEWPORT_SIZE) {
|
||||||
|
const expansion = (MIN_VIEWPORT_SIZE - finalViewBox.width) / 2;
|
||||||
|
finalViewBox.x = Math.max(0, finalViewBox.x - expansion);
|
||||||
|
finalViewBox.width = Math.min(MIN_VIEWPORT_SIZE, 100 - finalViewBox.x);
|
||||||
|
}
|
||||||
|
if (finalViewBox.height < MIN_VIEWPORT_SIZE) {
|
||||||
|
const expansion = (MIN_VIEWPORT_SIZE - finalViewBox.height) / 2;
|
||||||
|
finalViewBox.y = Math.max(0, finalViewBox.y - expansion);
|
||||||
|
finalViewBox.height = Math.min(MIN_VIEWPORT_SIZE, 100 - finalViewBox.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply transformation
|
||||||
|
const scale = 100 / finalViewBox.width;
|
||||||
|
const translateX = -finalViewBox.x;
|
||||||
|
const translateY = -finalViewBox.y;
|
||||||
|
|
||||||
|
const transformValue = `scale(${scale}) translate(${translateX}%, ${translateY}%)`;
|
||||||
|
const transformWrapper = this.querySelector(".transform-wrapper");
|
||||||
|
if (transformWrapper) {
|
||||||
|
transformWrapper.style.transform = transformValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showTooltip(event) {
|
||||||
|
const point = event.target;
|
||||||
|
const tooltipText = point.dataset.tooltipText;
|
||||||
|
|
||||||
|
if (this.tooltip && tooltipText) {
|
||||||
|
this.tooltip.textContent = tooltipText;
|
||||||
|
this.updateTooltipPosition(event);
|
||||||
|
this.tooltip.classList.remove("opacity-0");
|
||||||
|
this.tooltip.classList.add("opacity-100");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideTooltip() {
|
||||||
|
if (this.tooltip) {
|
||||||
|
this.tooltip.classList.remove("opacity-100");
|
||||||
|
this.tooltip.classList.add("opacity-0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTooltipPosition(event) {
|
||||||
|
if (!this.tooltip) return;
|
||||||
|
|
||||||
|
const mapRect = this.mapElement.getBoundingClientRect();
|
||||||
|
const x = event.clientX - mapRect.left;
|
||||||
|
const y = event.clientY - mapRect.top;
|
||||||
|
|
||||||
|
this.tooltip.style.left = `${x}px`;
|
||||||
|
this.tooltip.style.top = `${y}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Register the custom elements
|
// Register the custom elements
|
||||||
customElements.define("places-filter", PlacesFilter);
|
customElements.define("places-filter", PlacesFilter);
|
||||||
customElements.define("place-accordion", PlaceAccordion);
|
customElements.define("place-accordion", PlaceAccordion);
|
||||||
customElements.define("places-map", PlacesMap);
|
customElements.define("places-map", PlacesMap);
|
||||||
|
customElements.define("places-map-single", PlacesMapSingle);
|
||||||
|
|||||||
Reference in New Issue
Block a user