@websline/cms-view-utils 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -0
- package/src/components/PageRenderer.astro +28 -0
- package/src/data/index.js +1 -0
- package/src/data/pageData.js +37 -0
- package/src/index.js +3 -0
- package/src/utils/iframeDragHandler.js +190 -0
- package/src/utils/index.js +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@websline/cms-view-utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"astro": "^5.8.0",
|
|
14
|
+
"svelte": "^5.33.0"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {}
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { fetchPageData } from "../data/pageData";
|
|
3
|
+
|
|
4
|
+
const { lang, slug } = Astro.params;
|
|
5
|
+
const url = new URL(Astro.request.url);
|
|
6
|
+
const searchParams = url.searchParams;
|
|
7
|
+
|
|
8
|
+
// const isPreviewMode = searchParams.get("editable") === "true";
|
|
9
|
+
|
|
10
|
+
await fetchPageData(Astro.locals, lang, slug);
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<slot />
|
|
14
|
+
|
|
15
|
+
<!--
|
|
16
|
+
{isPreviewMode && (
|
|
17
|
+
|
|
18
|
+
<style>
|
|
19
|
+
.cms-block-dropzones {
|
|
20
|
+
padding: 2rem;
|
|
21
|
+
border: 2px dashed #999;
|
|
22
|
+
min-height: 50px;
|
|
23
|
+
}
|
|
24
|
+
.cms-block-dropzones.highlight {
|
|
25
|
+
border-color: rgb(106, 106, 255);
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
)} -->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./pageData";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export async function fetchPageData(locals, lang, slug) {
|
|
2
|
+
const API_BASE = import.meta.env.PUBLIC_API_URL?.replace(/\/+$/, ""); // Remove trailing slashes
|
|
3
|
+
if (!API_BASE) throw new Error("PUBLIC_API_URL ist nicht gesetzt.");
|
|
4
|
+
|
|
5
|
+
const key = `__pageData__${lang}__${slug}`;
|
|
6
|
+
|
|
7
|
+
if (!locals[key]) {
|
|
8
|
+
console.log("from fetch");
|
|
9
|
+
const url = `${API_BASE}/${lang}/pages/${slug}`;
|
|
10
|
+
const res = await fetch(url);
|
|
11
|
+
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Fehler beim Abrufen der Seite: ${res.status} ${res.statusText}`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
locals[key] = await res.json();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
locals.__currentPageKey = key;
|
|
22
|
+
return locals[key];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getPageData(locals) {
|
|
26
|
+
const key = locals.__currentPageKey;
|
|
27
|
+
|
|
28
|
+
if (!key || !locals[key]) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"getPageData() wurde aufgerufen, bevor fetchPageData() ausgeführt wurde."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log("from cache");
|
|
35
|
+
|
|
36
|
+
return locals[key];
|
|
37
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// Handler for mouse follower behavior inside the iframe
|
|
2
|
+
class IframeDragHandler {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.mouseFollowerWidth = 48;
|
|
5
|
+
this.mouseFollowerHeight = 48;
|
|
6
|
+
|
|
7
|
+
this.handleMouseMove = (event) => {
|
|
8
|
+
this.updateMouseFollowerPosition(event);
|
|
9
|
+
this.checkMouseLeaveFrame();
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
window.addEventListener("message", (event) => {
|
|
13
|
+
const { owner, type } = event.data;
|
|
14
|
+
if (owner !== "dragging") return;
|
|
15
|
+
|
|
16
|
+
if (type === "startDragging") {
|
|
17
|
+
this.enableDragging();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (type === "stopDragging") {
|
|
21
|
+
this.disableDragging();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (type === "enterIframeWhileDragging") {
|
|
25
|
+
this.showMouseFollower();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (type === "leaveIframeWhileDragging") {
|
|
29
|
+
this.hideMouseFollower();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Enables drag mode inside the iframe
|
|
35
|
+
enableDragging() {
|
|
36
|
+
this.addStopDraggingHandler();
|
|
37
|
+
this.addMouseFollowerToDOM();
|
|
38
|
+
this.addMouseFollowerHandler();
|
|
39
|
+
this.highlightDropzone();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Disables drag mode
|
|
43
|
+
disableDragging() {
|
|
44
|
+
this.removeStopDraggingHandler();
|
|
45
|
+
this.removeMouseFollowerFromDOM();
|
|
46
|
+
this.removeMouseFollowerHandler();
|
|
47
|
+
this.unhighlightDropzone();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Adds a listener for mouseup to stop dragging
|
|
51
|
+
addStopDraggingHandler() {
|
|
52
|
+
window.addEventListener("mouseup", this.stopDragging);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Removes the mouseup listener
|
|
56
|
+
removeStopDraggingHandler() {
|
|
57
|
+
window.removeEventListener("mouseup", this.stopDragging);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Stops dragging and notifies the parent
|
|
61
|
+
stopDragging = () => {
|
|
62
|
+
this.sendParentMessage({
|
|
63
|
+
owner: "iframe",
|
|
64
|
+
type: "stopDragging",
|
|
65
|
+
});
|
|
66
|
+
this.removeStopDraggingHandler();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Adds mouse follower element to the DOM
|
|
70
|
+
addMouseFollowerToDOM() {
|
|
71
|
+
if (this.mouseFollowerInDOM()) return;
|
|
72
|
+
|
|
73
|
+
const div = document.createElement("div");
|
|
74
|
+
div.className = "mouse-follower";
|
|
75
|
+
|
|
76
|
+
Object.assign(div.style, {
|
|
77
|
+
position: "absolute",
|
|
78
|
+
zIndex: "9999",
|
|
79
|
+
pointerEvents: "none",
|
|
80
|
+
left: `-${this.mouseFollowerWidth}px`,
|
|
81
|
+
top: `-${this.mouseFollowerHeight}px`,
|
|
82
|
+
width: this.mouseFollowerWidth + "px",
|
|
83
|
+
height: this.mouseFollowerHeight + "px",
|
|
84
|
+
background: "url(/drag-component.svg) no-repeat center center",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
document.body.appendChild(div);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Adds the mousemove listener
|
|
91
|
+
addMouseFollowerHandler() {
|
|
92
|
+
window.addEventListener("mousemove", this.handleMouseMove);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Removes the mousemove listener
|
|
96
|
+
removeMouseFollowerHandler() {
|
|
97
|
+
window.removeEventListener("mousemove", this.handleMouseMove);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Updates mouse follower position on mouse move
|
|
101
|
+
updateMouseFollowerPosition(event) {
|
|
102
|
+
const div = this.getMouseFollower();
|
|
103
|
+
if (div) {
|
|
104
|
+
div.style.left = `${event.clientX - this.mouseFollowerWidth / 2}px`;
|
|
105
|
+
div.style.top = `${event.clientY - this.mouseFollowerHeight / 2}px`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Checks if the mouse follower is outside the viewport
|
|
110
|
+
checkMouseLeaveFrame() {
|
|
111
|
+
const follower = this.getMouseFollower();
|
|
112
|
+
if (!follower) return;
|
|
113
|
+
|
|
114
|
+
const rect = follower.getBoundingClientRect();
|
|
115
|
+
const margin = 1;
|
|
116
|
+
|
|
117
|
+
const outOfBounds =
|
|
118
|
+
rect.left < -margin ||
|
|
119
|
+
rect.top < -margin ||
|
|
120
|
+
rect.right > window.innerWidth + margin ||
|
|
121
|
+
rect.bottom > window.innerHeight + margin;
|
|
122
|
+
|
|
123
|
+
if (outOfBounds && !follower.dataset._wasOutside) {
|
|
124
|
+
follower.dataset._wasOutside = "true";
|
|
125
|
+
this.hideMouseFollower();
|
|
126
|
+
this.sendParentMessage({ owner: "iframe", type: "leaveIframe" });
|
|
127
|
+
} else if (!outOfBounds && follower.dataset._wasOutside === "true") {
|
|
128
|
+
delete follower.dataset._wasOutside;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Hides the mouse follower
|
|
133
|
+
hideMouseFollower() {
|
|
134
|
+
const div = this.getMouseFollower();
|
|
135
|
+
if (div) {
|
|
136
|
+
div.style.display = "none";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Shows the mouse follower
|
|
141
|
+
showMouseFollower() {
|
|
142
|
+
const div = this.getMouseFollower();
|
|
143
|
+
if (div) {
|
|
144
|
+
div.style.display = "block";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Removes the mouse follower from DOM
|
|
149
|
+
removeMouseFollowerFromDOM() {
|
|
150
|
+
const div = this.getMouseFollower();
|
|
151
|
+
if (div) {
|
|
152
|
+
div.remove();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Checks whether the follower is in the DOM
|
|
157
|
+
mouseFollowerInDOM() {
|
|
158
|
+
return !!this.getMouseFollower();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Gets the follower element
|
|
162
|
+
getMouseFollower() {
|
|
163
|
+
return document.querySelector(".mouse-follower");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Sends a message to the parent window
|
|
167
|
+
sendParentMessage(message) {
|
|
168
|
+
window.parent.postMessage(message, "*");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Highlights the dropzone
|
|
172
|
+
highlightDropzone() {
|
|
173
|
+
const dropzones = document.querySelectorAll(".cms-block-dropzones");
|
|
174
|
+
|
|
175
|
+
dropzones.forEach((dropzone) => {
|
|
176
|
+
dropzone.classList.add("highlight");
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Removes highlight from dropzone
|
|
181
|
+
unhighlightDropzone() {
|
|
182
|
+
const dropzones = document.querySelectorAll(".cms-block-dropzones");
|
|
183
|
+
|
|
184
|
+
dropzones.forEach((dropzone) => {
|
|
185
|
+
dropzone.classList.remove("highlight");
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export default IframeDragHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./iframeDragHandler";
|