frontend-auto-cms 1.0.13 → 1.0.15
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/dist/runtime/dashboard.js +426 -371
- package/package.json +1 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const
|
|
1
|
+
const ve = "cms-export.patch.json", we = "frontend-auto-cms::content", re = "frontend-auto-cms::locales";
|
|
2
2
|
function oe(e) {
|
|
3
|
-
localStorage.setItem(
|
|
3
|
+
localStorage.setItem(we, JSON.stringify(e));
|
|
4
4
|
}
|
|
5
|
-
function
|
|
5
|
+
function se() {
|
|
6
6
|
try {
|
|
7
|
-
const e = localStorage.getItem(
|
|
7
|
+
const e = localStorage.getItem(re);
|
|
8
8
|
return e ? JSON.parse(e) : {};
|
|
9
9
|
} catch {
|
|
10
10
|
return {};
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
function I(e) {
|
|
14
|
-
localStorage.setItem(
|
|
14
|
+
localStorage.setItem(re, JSON.stringify(e));
|
|
15
15
|
}
|
|
16
16
|
async function ke() {
|
|
17
17
|
try {
|
|
@@ -24,7 +24,7 @@ async function ke() {
|
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
async function
|
|
27
|
+
async function ie() {
|
|
28
28
|
try {
|
|
29
29
|
const e = await fetch("/cms-locales.json", { cache: "no-store" });
|
|
30
30
|
if (!e.ok)
|
|
@@ -35,7 +35,7 @@ async function se() {
|
|
|
35
35
|
return {};
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
async function
|
|
38
|
+
async function $e() {
|
|
39
39
|
try {
|
|
40
40
|
const e = await fetch("/cms-route-map.json", { cache: "no-store" });
|
|
41
41
|
if (!e.ok)
|
|
@@ -47,8 +47,8 @@ async function we() {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
function Le(e) {
|
|
50
|
-
const t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), a = URL.createObjectURL(t),
|
|
51
|
-
|
|
50
|
+
const t = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), a = URL.createObjectURL(t), r = document.createElement("a");
|
|
51
|
+
r.href = a, r.download = ve, r.click(), URL.revokeObjectURL(a);
|
|
52
52
|
}
|
|
53
53
|
function A(e) {
|
|
54
54
|
return e.replace(/[^\w]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
@@ -60,46 +60,46 @@ function v(e) {
|
|
|
60
60
|
const a = (e.getAttribute("class") ?? "").split(/\s+/).filter(Boolean)[0];
|
|
61
61
|
return a ? `${e.tagName.toLowerCase()}.${a}` : e.tagName.toLowerCase();
|
|
62
62
|
}
|
|
63
|
-
function
|
|
63
|
+
function le(e) {
|
|
64
64
|
return ["SCRIPT", "STYLE", "NOSCRIPT", "IFRAME"].includes(e.tagName);
|
|
65
65
|
}
|
|
66
66
|
function N(e) {
|
|
67
67
|
return (e ?? "").replace(/\s+/g, " ").trim();
|
|
68
68
|
}
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
69
|
+
function Se(e, t, a) {
|
|
70
|
+
const r = t.parentElement;
|
|
71
|
+
if (!r || le(r))
|
|
72
72
|
return null;
|
|
73
|
-
if (Array.from(
|
|
73
|
+
if (Array.from(r.childNodes).filter(
|
|
74
74
|
(s) => s.nodeType === Node.TEXT_NODE && N(s.nodeValue).length > 0
|
|
75
|
-
).length === 1 &&
|
|
76
|
-
return
|
|
77
|
-
const
|
|
78
|
-
return
|
|
75
|
+
).length === 1 && r.children.length === 0)
|
|
76
|
+
return r.setAttribute("data-cms-key", a), r;
|
|
77
|
+
const o = e.createElement("span");
|
|
78
|
+
return o.textContent = t.nodeValue ?? "", o.setAttribute("data-cms-key", a), t.parentNode?.replaceChild(o, t), o;
|
|
79
79
|
}
|
|
80
80
|
function S(e = document, t) {
|
|
81
81
|
const a = [];
|
|
82
|
-
let
|
|
83
|
-
const i = t ?? e.location?.pathname ?? location.pathname,
|
|
84
|
-
if (!
|
|
82
|
+
let r = 0, n = 0, o = 0, s = 0;
|
|
83
|
+
const i = t ?? e.location?.pathname ?? location.pathname, l = e.body;
|
|
84
|
+
if (!l)
|
|
85
85
|
return {
|
|
86
86
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
87
87
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
88
88
|
nodes: a
|
|
89
89
|
};
|
|
90
|
-
const u = e.createTreeWalker(
|
|
90
|
+
const u = e.createTreeWalker(l, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
|
|
91
91
|
for (; u.nextNode(); ) {
|
|
92
92
|
const d = u.currentNode;
|
|
93
93
|
if (d.nodeType === Node.TEXT_NODE) {
|
|
94
94
|
const b = d, m = N(b.nodeValue);
|
|
95
95
|
if (m.length < 2)
|
|
96
96
|
continue;
|
|
97
|
-
|
|
98
|
-
const J = `${A(i || "index")}.text.${
|
|
97
|
+
r += 1;
|
|
98
|
+
const J = `${A(i || "index")}.text.${r}`, O = Se(e, b, J);
|
|
99
99
|
if (!O)
|
|
100
100
|
continue;
|
|
101
101
|
a.push({
|
|
102
|
-
id: `dom_txt_${
|
|
102
|
+
id: `dom_txt_${r}`,
|
|
103
103
|
key: J,
|
|
104
104
|
type: "text",
|
|
105
105
|
label: v(O),
|
|
@@ -109,47 +109,47 @@ function S(e = document, t) {
|
|
|
109
109
|
});
|
|
110
110
|
continue;
|
|
111
111
|
}
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
112
|
+
const c = d;
|
|
113
|
+
if (le(c))
|
|
114
114
|
continue;
|
|
115
|
-
const p =
|
|
115
|
+
const p = c.tagName.toLowerCase();
|
|
116
116
|
if (p === "img" || p === "video") {
|
|
117
|
-
const b =
|
|
117
|
+
const b = c.getAttribute("src") ?? "";
|
|
118
118
|
if (b) {
|
|
119
119
|
n += 1;
|
|
120
120
|
const m = `${A(i || "index")}.${p}.${n}`;
|
|
121
|
-
|
|
121
|
+
c.setAttribute("data-cms-key", m), a.push({
|
|
122
122
|
id: `dom_media_${n}`,
|
|
123
123
|
key: m,
|
|
124
124
|
type: p === "img" ? "image" : "video",
|
|
125
|
-
label: v(
|
|
125
|
+
label: v(c),
|
|
126
126
|
value: b,
|
|
127
|
-
selector: v(
|
|
128
|
-
attrs: { src: b, alt:
|
|
127
|
+
selector: v(c),
|
|
128
|
+
attrs: { src: b, alt: c.getAttribute("alt") ?? "" },
|
|
129
129
|
sourceRefs: [{ file: i, original: b }]
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
if (["section", "ul", "ol"].includes(p) ||
|
|
134
|
-
const b = Array.from(
|
|
133
|
+
if (["section", "ul", "ol"].includes(p) || c.hasAttribute("data-repeatable")) {
|
|
134
|
+
const b = Array.from(c.children).map((m) => N(m.textContent)).filter(Boolean);
|
|
135
135
|
if (b.length >= 2) {
|
|
136
|
-
|
|
137
|
-
const m = `${A(i || "index")}.section.${
|
|
138
|
-
|
|
139
|
-
id: `dom_sec_${
|
|
136
|
+
o += 1;
|
|
137
|
+
const m = `${A(i || "index")}.section.${o}`;
|
|
138
|
+
c.setAttribute("data-cms-key", m), a.push({
|
|
139
|
+
id: `dom_sec_${o}`,
|
|
140
140
|
key: m,
|
|
141
141
|
type: "section",
|
|
142
|
-
label: v(
|
|
142
|
+
label: v(c),
|
|
143
143
|
value: b.join(" | "),
|
|
144
|
-
selector: v(
|
|
144
|
+
selector: v(c),
|
|
145
145
|
sectionItems: b,
|
|
146
|
-
sourceRefs: [{ file: i, original:
|
|
146
|
+
sourceRefs: [{ file: i, original: c.innerHTML }]
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
const g = {};
|
|
151
151
|
if (["alt", "href", "src", "aria-label", "title"].forEach((b) => {
|
|
152
|
-
const m =
|
|
152
|
+
const m = c.getAttribute(b);
|
|
153
153
|
m != null && m.trim() && (g[b] = m);
|
|
154
154
|
}), Object.keys(g).length > 0 && !(p === "img" || p === "video")) {
|
|
155
155
|
s += 1;
|
|
@@ -158,9 +158,9 @@ function S(e = document, t) {
|
|
|
158
158
|
id: `dom_prop_${s}`,
|
|
159
159
|
key: b,
|
|
160
160
|
type: "property",
|
|
161
|
-
label: v(
|
|
161
|
+
label: v(c),
|
|
162
162
|
value: JSON.stringify(g),
|
|
163
|
-
selector: v(
|
|
163
|
+
selector: v(c),
|
|
164
164
|
attrs: g,
|
|
165
165
|
sourceRefs: [{ file: i, original: JSON.stringify(g) }]
|
|
166
166
|
});
|
|
@@ -172,7 +172,7 @@ function S(e = document, t) {
|
|
|
172
172
|
nodes: a
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
|
-
function
|
|
175
|
+
function B(e, t = document) {
|
|
176
176
|
if (!e.key)
|
|
177
177
|
return;
|
|
178
178
|
const a = t.querySelector(`[data-cms-key="${CSS.escape(e.key)}"]`);
|
|
@@ -182,16 +182,16 @@ function P(e, t = document) {
|
|
|
182
182
|
else if (e.type === "image" || e.type === "video")
|
|
183
183
|
a.src = e.value, e.attrs?.alt != null && a.setAttribute("alt", e.attrs.alt);
|
|
184
184
|
else if (e.type === "property" && e.attrs)
|
|
185
|
-
Object.entries(e.attrs).forEach(([
|
|
185
|
+
Object.entries(e.attrs).forEach(([r, n]) => a.setAttribute(r, n));
|
|
186
186
|
else if (e.type === "section" && e.sectionItems) {
|
|
187
|
-
const
|
|
188
|
-
e.sectionItems.forEach((n,
|
|
189
|
-
o
|
|
187
|
+
const r = Array.from(a.children);
|
|
188
|
+
e.sectionItems.forEach((n, o) => {
|
|
189
|
+
r[o] && (r[o].textContent = n);
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
-
const
|
|
194
|
+
const P = [
|
|
195
195
|
{ code: "af", label: "Afrikaans", nllb: "afr_Latn" },
|
|
196
196
|
{ code: "ar", label: "Arabic", nllb: "arb_Arab" },
|
|
197
197
|
{ code: "az", label: "Azerbaijani", nllb: "azj_Latn" },
|
|
@@ -257,8 +257,8 @@ const B = [
|
|
|
257
257
|
{ code: "vi", label: "Vietnamese", nllb: "vie_Latn" },
|
|
258
258
|
{ code: "zh", label: "Chinese (Simplified)", nllb: "zho_Hans" }
|
|
259
259
|
], W = Object.fromEntries(
|
|
260
|
-
|
|
261
|
-
),
|
|
260
|
+
P.map((e) => [e.nllb.slice(0, 3).toLowerCase(), e.code])
|
|
261
|
+
), Ee = "https://api.mymemory.translated.net/get";
|
|
262
262
|
function Y(e) {
|
|
263
263
|
const t = e.trim().toLowerCase().split(/[-_]/)[0];
|
|
264
264
|
if (/^[a-z]{2}$/i.test(t))
|
|
@@ -267,46 +267,46 @@ function Y(e) {
|
|
|
267
267
|
return W[t];
|
|
268
268
|
throw new Error(`Unsupported language code "${e}" for MyMemory translation.`);
|
|
269
269
|
}
|
|
270
|
-
async function
|
|
270
|
+
async function _e(e, t, a) {
|
|
271
271
|
if (!e.trim())
|
|
272
272
|
return e;
|
|
273
|
-
const
|
|
273
|
+
const r = new URLSearchParams({
|
|
274
274
|
q: e,
|
|
275
275
|
langpair: `${t}|${a}`
|
|
276
|
-
}), n = await fetch(`${
|
|
276
|
+
}), n = await fetch(`${Ee}?${r.toString()}`, { method: "GET" });
|
|
277
277
|
if (!n.ok)
|
|
278
278
|
throw new Error(`MyMemory request failed (${n.status})`);
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
281
|
-
throw new Error(`MyMemory translation failed with status ${
|
|
282
|
-
const s =
|
|
279
|
+
const o = await n.json();
|
|
280
|
+
if (o.responseStatus && o.responseStatus !== 200)
|
|
281
|
+
throw new Error(`MyMemory translation failed with status ${o.responseStatus}`);
|
|
282
|
+
const s = o.responseData?.translatedText;
|
|
283
283
|
return typeof s == "string" && s.trim() ? s : e;
|
|
284
284
|
}
|
|
285
|
-
async function
|
|
286
|
-
const n = Y(a),
|
|
285
|
+
async function Ae(e, t, a = "en", r) {
|
|
286
|
+
const n = Y(a), o = Y(t), s = /* @__PURE__ */ new Map(), i = {}, l = Object.entries(e), u = l.length;
|
|
287
287
|
let d = 0;
|
|
288
|
-
for (const [
|
|
288
|
+
for (const [c, p] of l) {
|
|
289
289
|
if (s.has(p)) {
|
|
290
|
-
i[
|
|
290
|
+
i[c] = s.get(p), d += 1, r?.(d, u);
|
|
291
291
|
continue;
|
|
292
292
|
}
|
|
293
293
|
try {
|
|
294
|
-
const g = await
|
|
295
|
-
s.set(p, g), i[
|
|
294
|
+
const g = await _e(p, n, o);
|
|
295
|
+
s.set(p, g), i[c] = g;
|
|
296
296
|
} catch {
|
|
297
|
-
i[
|
|
297
|
+
i[c] = p;
|
|
298
298
|
}
|
|
299
|
-
d += 1,
|
|
299
|
+
d += 1, r?.(d, u);
|
|
300
300
|
}
|
|
301
301
|
return i;
|
|
302
302
|
}
|
|
303
|
-
function
|
|
303
|
+
function ce(e) {
|
|
304
304
|
return /^[^/\s]+\/[^/\s]+$/.test(e);
|
|
305
305
|
}
|
|
306
|
-
function
|
|
306
|
+
function de(e) {
|
|
307
307
|
return /^([^/\s]+\/)+[^/\s]+$/.test(e);
|
|
308
308
|
}
|
|
309
|
-
async function
|
|
309
|
+
async function Te(e, t, a) {
|
|
310
310
|
return (await fetch(
|
|
311
311
|
`https://gitlab.com/api/v4/projects/${encodeURIComponent(e.repository)}/repository/files/${encodeURIComponent(a)}?ref=${encodeURIComponent(e.branch)}`,
|
|
312
312
|
{
|
|
@@ -315,7 +315,7 @@ async function Ae(e, t, a) {
|
|
|
315
315
|
}
|
|
316
316
|
)).ok;
|
|
317
317
|
}
|
|
318
|
-
async function
|
|
318
|
+
async function Ie() {
|
|
319
319
|
try {
|
|
320
320
|
const e = await fetch("/cms-hosting.json", { cache: "no-store" });
|
|
321
321
|
if (!e.ok)
|
|
@@ -324,120 +324,175 @@ async function Te() {
|
|
|
324
324
|
if (!t || !t.provider || t.provider === "none" || t.provider !== "github" && t.provider !== "gitlab" || typeof t.repository != "string" || !t.repository.trim())
|
|
325
325
|
return null;
|
|
326
326
|
const a = t.repository.trim();
|
|
327
|
-
return t.provider === "github" && !
|
|
327
|
+
return t.provider === "github" && !ce(a) || t.provider === "gitlab" && !de(a) || typeof t.branch != "string" || !t.branch.trim() ? null : { ...t, repository: a, branch: t.branch.trim() };
|
|
328
328
|
} catch {
|
|
329
329
|
return null;
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
|
-
async function
|
|
333
|
-
const
|
|
332
|
+
async function L(e, t, a, r, n) {
|
|
333
|
+
const o = `https://api.github.com/repos/${e.repository}/contents/${encodeURIComponent(a).replace(/%2F/g, "/")}`;
|
|
334
334
|
let s;
|
|
335
|
-
const i = await fetch(`${
|
|
335
|
+
const i = await fetch(`${o}?ref=${encodeURIComponent(e.branch)}`, {
|
|
336
336
|
headers: { Authorization: `Bearer ${t}` }
|
|
337
337
|
});
|
|
338
338
|
i.ok && (s = (await i.json()).sha);
|
|
339
|
-
const
|
|
339
|
+
const l = {
|
|
340
340
|
message: n,
|
|
341
|
-
content: btoa(unescape(encodeURIComponent(
|
|
341
|
+
content: btoa(unescape(encodeURIComponent(r))),
|
|
342
342
|
branch: e.branch,
|
|
343
343
|
sha: s
|
|
344
344
|
};
|
|
345
|
-
if (!(await fetch(
|
|
345
|
+
if (!(await fetch(o, {
|
|
346
346
|
method: "PUT",
|
|
347
347
|
headers: {
|
|
348
348
|
Authorization: `Bearer ${t}`,
|
|
349
349
|
"Content-Type": "application/json"
|
|
350
350
|
},
|
|
351
|
-
body: JSON.stringify(
|
|
351
|
+
body: JSON.stringify(l)
|
|
352
352
|
})).ok)
|
|
353
353
|
throw new Error(`GitHub publish failed for ${a}`);
|
|
354
354
|
}
|
|
355
|
-
function
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
355
|
+
async function V(e, t, a) {
|
|
356
|
+
return (await fetch(`https://api.github.com/repos/${e.repository}/branches/${encodeURIComponent(a)}`, {
|
|
357
|
+
headers: { Authorization: `Bearer ${t}` }
|
|
358
|
+
})).ok;
|
|
359
|
+
}
|
|
360
|
+
async function Ce(e, t) {
|
|
361
|
+
const a = await fetch(`https://api.github.com/repos/${e.repository}`, {
|
|
362
|
+
headers: { Authorization: `Bearer ${t}` }
|
|
363
|
+
});
|
|
364
|
+
return a.ok && (await a.json()).default_branch?.trim() || null;
|
|
365
|
+
}
|
|
366
|
+
async function je(e, t) {
|
|
367
|
+
const a = e.branch.trim();
|
|
368
|
+
if (await V(e, t, a))
|
|
369
|
+
return { ...e, branch: a };
|
|
370
|
+
const r = await Ce(e, t);
|
|
371
|
+
if (!r)
|
|
372
|
+
throw new Error(`Configured branch "${a}" was not found and repo default branch could not be resolved.`);
|
|
373
|
+
if (!await V(e, t, r))
|
|
374
|
+
throw new Error(`Configured branch "${a}" was not found. Resolved default branch "${r}" is also unavailable.`);
|
|
375
|
+
return { ...e, branch: r };
|
|
376
|
+
}
|
|
377
|
+
function Oe(e) {
|
|
378
|
+
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
379
|
+
}
|
|
380
|
+
function ze(e, t, a, r = 1) {
|
|
381
|
+
if (!t || r < 1)
|
|
382
|
+
return { content: e, replaced: !1 };
|
|
383
|
+
let n = -1, o = 0;
|
|
384
|
+
for (let s = 0; s < r; s += 1) {
|
|
385
|
+
if (n = e.indexOf(t, o), n < 0)
|
|
386
|
+
return { content: e, replaced: !1 };
|
|
387
|
+
o = n + t.length;
|
|
363
388
|
}
|
|
364
|
-
return
|
|
389
|
+
return {
|
|
390
|
+
content: `${e.slice(0, n)}${a}${e.slice(n + t.length)}`,
|
|
391
|
+
replaced: !0
|
|
392
|
+
};
|
|
365
393
|
}
|
|
366
|
-
function
|
|
394
|
+
function Ne(e, t, a, r = 1) {
|
|
395
|
+
if (!t || r < 1)
|
|
396
|
+
return { content: e, replaced: !1 };
|
|
397
|
+
const n = t.trim().split(/\s+/).filter(Boolean);
|
|
398
|
+
if (!n.length)
|
|
399
|
+
return { content: e, replaced: !1 };
|
|
400
|
+
const o = n.map((u) => Oe(u)).join("\\s+"), s = new RegExp(o, "g");
|
|
401
|
+
let i = null, l = 0;
|
|
402
|
+
for (; (i = s.exec(e)) !== null; ) {
|
|
403
|
+
if (l += 1, l !== r)
|
|
404
|
+
continue;
|
|
405
|
+
const u = i.index, d = u + i[0].length;
|
|
406
|
+
return {
|
|
407
|
+
content: `${e.slice(0, u)}${a}${e.slice(d)}`,
|
|
408
|
+
replaced: !0
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return { content: e, replaced: !1 };
|
|
412
|
+
}
|
|
413
|
+
function Me(e) {
|
|
367
414
|
const t = (e ?? "").trim().replace(/\\/g, "/").replace(/^\/+/, "");
|
|
368
415
|
return !t || t.includes("..") ? null : t;
|
|
369
416
|
}
|
|
370
|
-
function
|
|
371
|
-
const t = atob(e.replace(/\s+/g, "")), a = Uint8Array.from(t, (
|
|
417
|
+
function Re(e) {
|
|
418
|
+
const t = atob(e.replace(/\s+/g, "")), a = Uint8Array.from(t, (r) => r.charCodeAt(0));
|
|
372
419
|
return new TextDecoder().decode(a);
|
|
373
420
|
}
|
|
374
|
-
async function
|
|
375
|
-
const
|
|
421
|
+
async function Be(e, t, a) {
|
|
422
|
+
const r = `https://api.github.com/repos/${e.repository}/contents/${encodeURIComponent(a).replace(/%2F/g, "/")}`, n = await fetch(`${r}?ref=${encodeURIComponent(e.branch)}`, {
|
|
376
423
|
headers: { Authorization: `Bearer ${t}` }
|
|
377
424
|
});
|
|
378
425
|
if (!n.ok)
|
|
379
426
|
return null;
|
|
380
|
-
const
|
|
381
|
-
return !
|
|
382
|
-
sha:
|
|
383
|
-
content:
|
|
427
|
+
const o = await n.json();
|
|
428
|
+
return !o.sha || !o.content || o.encoding !== "base64" ? null : {
|
|
429
|
+
sha: o.sha,
|
|
430
|
+
content: Re(o.content)
|
|
384
431
|
};
|
|
385
432
|
}
|
|
386
|
-
async function
|
|
433
|
+
async function Pe(e, t, a, r) {
|
|
387
434
|
const n = /* @__PURE__ */ new Map();
|
|
388
|
-
let
|
|
389
|
-
a.forEach((
|
|
390
|
-
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
435
|
+
let o = 0;
|
|
436
|
+
a.forEach((l) => {
|
|
437
|
+
l.find !== l.replace && (o += 1);
|
|
438
|
+
const u = Me(l.file);
|
|
439
|
+
if (!u)
|
|
393
440
|
return;
|
|
394
|
-
const
|
|
395
|
-
|
|
441
|
+
const d = n.get(u) ?? [];
|
|
442
|
+
d.push({ ...l, file: u }), n.set(u, d);
|
|
396
443
|
});
|
|
397
|
-
let s = 0;
|
|
398
|
-
for (const [
|
|
399
|
-
const
|
|
400
|
-
if (!
|
|
444
|
+
let s = 0, i = 0;
|
|
445
|
+
for (const [l, u] of n.entries()) {
|
|
446
|
+
const d = await Be(e, t, l);
|
|
447
|
+
if (!d)
|
|
401
448
|
continue;
|
|
402
|
-
let
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
449
|
+
let c = d.content;
|
|
450
|
+
u.forEach((p) => {
|
|
451
|
+
if (!p.find || p.find === p.replace)
|
|
452
|
+
return;
|
|
453
|
+
const g = ze(c, p.find, p.replace, p.occurrence ?? 1);
|
|
454
|
+
if (g.replaced) {
|
|
455
|
+
c = g.content, i += 1;
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const h = Ne(c, p.find, p.replace, p.occurrence ?? 1);
|
|
459
|
+
h.replaced && (c = h.content, i += 1);
|
|
460
|
+
}), c !== d.content && (await L(e, t, l, c, r), s += 1);
|
|
406
461
|
}
|
|
407
|
-
return { updatedFiles: s, attemptedFiles: n.size, actionableOperations:
|
|
462
|
+
return { updatedFiles: s, attemptedFiles: n.size, actionableOperations: o, appliedOperations: i };
|
|
408
463
|
}
|
|
409
|
-
async function
|
|
410
|
-
const
|
|
411
|
-
if (
|
|
464
|
+
async function De(e, t, a) {
|
|
465
|
+
const r = await je(e, t), n = `chore(cms): publish content updates ${(/* @__PURE__ */ new Date()).toISOString()}`, o = await Pe(r, t, a.operations ?? [], n);
|
|
466
|
+
if (o.actionableOperations > 0 && o.appliedOperations === 0)
|
|
412
467
|
throw new Error(
|
|
413
|
-
`No source files were updated (${
|
|
468
|
+
`No source files were updated (${o.attemptedFiles} candidate files checked). Run setup again to refresh cms-route-map.json and retry.`
|
|
414
469
|
);
|
|
415
|
-
if (await
|
|
416
|
-
for (const [
|
|
417
|
-
await
|
|
418
|
-
await
|
|
419
|
-
|
|
470
|
+
if (await L(r, t, "cms-content.json", JSON.stringify(a.content, null, 2), n), a.locales) {
|
|
471
|
+
for (const [s, i] of Object.entries(a.locales))
|
|
472
|
+
await L(r, t, `locales/${s}.json`, JSON.stringify(i, null, 2), n);
|
|
473
|
+
await L(
|
|
474
|
+
r,
|
|
420
475
|
t,
|
|
421
476
|
"cms-locales.json",
|
|
422
477
|
JSON.stringify({ version: 1, locales: a.locales }, null, 2),
|
|
423
|
-
|
|
478
|
+
n
|
|
424
479
|
);
|
|
425
480
|
}
|
|
426
|
-
await
|
|
481
|
+
await L(r, t, "cms-export.patch.json", JSON.stringify(a, null, 2), n);
|
|
427
482
|
}
|
|
428
|
-
async function
|
|
429
|
-
const
|
|
483
|
+
async function Ue(e, t, a) {
|
|
484
|
+
const r = [
|
|
430
485
|
{ filePath: "cms-content.json", content: JSON.stringify(a.content, null, 2) },
|
|
431
486
|
{ filePath: "cms-export.patch.json", content: JSON.stringify(a, null, 2) }
|
|
432
487
|
];
|
|
433
488
|
if (a.locales) {
|
|
434
489
|
for (const [s, i] of Object.entries(a.locales))
|
|
435
|
-
|
|
436
|
-
|
|
490
|
+
r.push({ filePath: `locales/${s}.json`, content: JSON.stringify(i, null, 2) });
|
|
491
|
+
r.push({ filePath: "cms-locales.json", content: JSON.stringify({ version: 1, locales: a.locales }, null, 2) });
|
|
437
492
|
}
|
|
438
493
|
const n = [];
|
|
439
|
-
for (const s of
|
|
440
|
-
const i = await
|
|
494
|
+
for (const s of r) {
|
|
495
|
+
const i = await Te(e, t, s.filePath);
|
|
441
496
|
n.push({
|
|
442
497
|
action: i ? "update" : "create",
|
|
443
498
|
file_path: s.filePath,
|
|
@@ -458,18 +513,18 @@ async function Me(e, t, a) {
|
|
|
458
513
|
})).ok)
|
|
459
514
|
throw new Error("GitLab publish failed.");
|
|
460
515
|
}
|
|
461
|
-
async function
|
|
516
|
+
async function Ge(e, t, a) {
|
|
462
517
|
if (!a || !t.trim())
|
|
463
518
|
return !1;
|
|
464
|
-
if (a.provider === "github" && !
|
|
519
|
+
if (a.provider === "github" && !ce(a.repository))
|
|
465
520
|
throw new Error('Invalid GitHub repository format. Use "owner/repo".');
|
|
466
|
-
if (a.provider === "gitlab" && !
|
|
521
|
+
if (a.provider === "gitlab" && !de(a.repository))
|
|
467
522
|
throw new Error('Invalid GitLab repository format. Use "group/project".');
|
|
468
|
-
return a.provider === "github" ? (await
|
|
523
|
+
return a.provider === "github" ? (await De(a, t.trim(), e), !0) : a.provider === "gitlab" ? (await Ue(a, t.trim(), e), !0) : !1;
|
|
469
524
|
}
|
|
470
|
-
const
|
|
471
|
-
let D = !1,
|
|
472
|
-
function
|
|
525
|
+
const X = "facms-auth-modal", M = "facms-auth-missing", Z = "facms-token-modal", Q = "facms-language-modal", He = "frontend-auto-cms::theme", ue = "frontend-auto-cms::main-language", fe = "frontend-auto-cms::language-labels";
|
|
526
|
+
let D = !1, w = null, ee = !1, x = null, f = "dark", U = {};
|
|
527
|
+
function pe() {
|
|
473
528
|
if (document.getElementById("facms-dashboard-css"))
|
|
474
529
|
return;
|
|
475
530
|
const e = document.createElement("style");
|
|
@@ -708,24 +763,24 @@ function fe() {
|
|
|
708
763
|
}
|
|
709
764
|
`, document.head.appendChild(e);
|
|
710
765
|
}
|
|
711
|
-
function
|
|
766
|
+
function ge(e) {
|
|
712
767
|
f = e;
|
|
713
768
|
const t = e === "dark";
|
|
714
|
-
document.documentElement.classList.toggle("dark", t), document.body.classList.toggle("dark", t), document.documentElement.style.background = t ? "#020617" : "#f1f5f9", document.body.style.background = t ? "#020617" : "#f1f5f9", document.documentElement.setAttribute("data-facms-theme", e), document.getElementById("facms-app")?.classList.toggle("dark", t), localStorage.setItem(
|
|
715
|
-
const
|
|
716
|
-
|
|
769
|
+
document.documentElement.classList.toggle("dark", t), document.body.classList.toggle("dark", t), document.documentElement.style.background = t ? "#020617" : "#f1f5f9", document.body.style.background = t ? "#020617" : "#f1f5f9", document.documentElement.setAttribute("data-facms-theme", e), document.getElementById("facms-app")?.classList.toggle("dark", t), localStorage.setItem(He, e);
|
|
770
|
+
const r = document.getElementById("facms-theme-toggle");
|
|
771
|
+
r && (r.textContent = e === "dark" ? "Switch to light" : "Switch to dark");
|
|
717
772
|
}
|
|
718
|
-
function
|
|
719
|
-
f = "dark",
|
|
773
|
+
function be() {
|
|
774
|
+
f = "dark", ge("dark");
|
|
720
775
|
}
|
|
721
|
-
function
|
|
776
|
+
function qe(e) {
|
|
722
777
|
return Array.from(new Uint8Array(e)).map((t) => t.toString(16).padStart(2, "0")).join("");
|
|
723
778
|
}
|
|
724
|
-
async function
|
|
779
|
+
async function Ke(e) {
|
|
725
780
|
const t = new TextEncoder().encode(e), a = await crypto.subtle.digest("SHA-256", t);
|
|
726
|
-
return
|
|
781
|
+
return qe(a);
|
|
727
782
|
}
|
|
728
|
-
async function
|
|
783
|
+
async function me() {
|
|
729
784
|
if (x)
|
|
730
785
|
return x;
|
|
731
786
|
try {
|
|
@@ -744,23 +799,23 @@ async function be() {
|
|
|
744
799
|
return x = { dashboardPath: "/dashboard", pages: ["/"], showFloatingButton: !1, autoTranslateEnabled: !0 }, x;
|
|
745
800
|
}
|
|
746
801
|
async function G() {
|
|
747
|
-
if (!
|
|
748
|
-
|
|
802
|
+
if (!ee) {
|
|
803
|
+
ee = !0;
|
|
749
804
|
try {
|
|
750
805
|
const e = await fetch("/cms-runtime-auth.json", { cache: "no-store" });
|
|
751
806
|
if (!e.ok) return;
|
|
752
807
|
const t = await e.json();
|
|
753
|
-
t.algorithm === "sha256" && typeof t.salt == "string" && typeof t.passcodeHash == "string" && (
|
|
808
|
+
t.algorithm === "sha256" && typeof t.salt == "string" && typeof t.passcodeHash == "string" && (w = { algorithm: "sha256", salt: t.salt, passcodeHash: t.passcodeHash });
|
|
754
809
|
} catch {
|
|
755
|
-
|
|
810
|
+
w = null;
|
|
756
811
|
}
|
|
757
812
|
}
|
|
758
813
|
}
|
|
759
|
-
async function
|
|
814
|
+
async function Fe(e) {
|
|
760
815
|
const t = e.trim();
|
|
761
|
-
return !t || (await G(), !
|
|
816
|
+
return !t || (await G(), !w) ? !1 : await Ke(`${w.salt}:${t}`) === w.passcodeHash;
|
|
762
817
|
}
|
|
763
|
-
function
|
|
818
|
+
function Je() {
|
|
764
819
|
let e = document.getElementById(M);
|
|
765
820
|
e || (e = document.createElement("div"), e.id = M, e.style.position = "fixed", e.style.inset = "0", e.style.zIndex = "2147483647", e.style.background = "rgba(2, 6, 23, 0.88)", e.style.display = "grid", e.style.placeItems = "center", e.innerHTML = `
|
|
766
821
|
<div style="width:min(560px,92vw);background:#0f172a;color:#e2e8f0;border:1px solid #334155;border-radius:16px;padding:16px;box-shadow:0 20px 55px rgba(2,6,23,.45);font-family:Inter,system-ui,sans-serif;">
|
|
@@ -770,20 +825,20 @@ function Ge() {
|
|
|
770
825
|
</div>
|
|
771
826
|
`, document.body.appendChild(e));
|
|
772
827
|
}
|
|
773
|
-
function
|
|
828
|
+
function We() {
|
|
774
829
|
document.getElementById(M)?.remove();
|
|
775
830
|
}
|
|
776
|
-
async function
|
|
777
|
-
return await G(),
|
|
831
|
+
async function he() {
|
|
832
|
+
return await G(), w ? (We(), !0) : (Je(), !1);
|
|
778
833
|
}
|
|
779
|
-
function
|
|
780
|
-
const t = document.getElementById(
|
|
834
|
+
function ye(e) {
|
|
835
|
+
const t = document.getElementById(X);
|
|
781
836
|
if (t) {
|
|
782
837
|
t.style.display = "grid";
|
|
783
838
|
return;
|
|
784
839
|
}
|
|
785
840
|
const a = document.createElement("div");
|
|
786
|
-
a.id =
|
|
841
|
+
a.id = X, a.style.position = "fixed", a.style.inset = "0", a.style.zIndex = "2147483647", a.style.background = "rgba(2, 6, 23, 0.45)", a.style.display = "grid", a.style.placeItems = "center", a.innerHTML = `
|
|
787
842
|
<div style="width: min(420px, 92vw); background: ${f === "dark" ? "#0f172a" : "#ffffff"}; color: ${f === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${f === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
|
|
788
843
|
<h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Unlock CMS</h3>
|
|
789
844
|
<p style="margin: 0 0 12px 0; font-size: 12px; color: ${f === "dark" ? "#94a3b8" : "#475569"};">Enter your passcode to edit content.</p>
|
|
@@ -795,24 +850,24 @@ function he(e) {
|
|
|
795
850
|
</div>
|
|
796
851
|
</div>
|
|
797
852
|
`;
|
|
798
|
-
const
|
|
799
|
-
if (await G(), !
|
|
853
|
+
const r = a.querySelector("#facms-passcode-input"), n = a.querySelector("#facms-passcode-error"), o = () => a.style.display = "none", s = async () => {
|
|
854
|
+
if (await G(), !w) {
|
|
800
855
|
n && (n.textContent = "CMS auth is not configured. Run setup to generate runtime auth files.", n.style.display = "block");
|
|
801
856
|
return;
|
|
802
857
|
}
|
|
803
|
-
if (!await
|
|
858
|
+
if (!await Fe(r?.value ?? "")) {
|
|
804
859
|
n && (n.textContent = "Incorrect passcode.", n.style.display = "block");
|
|
805
860
|
return;
|
|
806
861
|
}
|
|
807
|
-
n && (n.style.display = "none"), D = !0,
|
|
862
|
+
n && (n.style.display = "none"), D = !0, o(), e();
|
|
808
863
|
};
|
|
809
|
-
a.querySelector("#facms-passcode-cancel")?.addEventListener("click",
|
|
864
|
+
a.querySelector("#facms-passcode-cancel")?.addEventListener("click", o), a.querySelector("#facms-passcode-submit")?.addEventListener("click", s), r?.addEventListener("keydown", (i) => i.key === "Enter" && void s()), document.body.appendChild(a), r?.focus();
|
|
810
865
|
}
|
|
811
|
-
function
|
|
812
|
-
const a = document.getElementById(
|
|
866
|
+
function Ye(e, t) {
|
|
867
|
+
const a = document.getElementById(Z);
|
|
813
868
|
a && a.remove();
|
|
814
|
-
const
|
|
815
|
-
|
|
869
|
+
const r = document.createElement("div");
|
|
870
|
+
r.id = Z, r.style.position = "fixed", r.style.inset = "0", r.style.zIndex = "2147483647", r.style.background = "rgba(2, 6, 23, 0.45)", r.style.display = "grid", r.style.placeItems = "center", r.innerHTML = `
|
|
816
871
|
<div style="width: min(520px, 92vw); background: ${f === "dark" ? "#0f172a" : "#ffffff"}; color: ${f === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${f === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
|
|
817
872
|
<h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Publish token required</h3>
|
|
818
873
|
<p style="margin: 0 0 12px 0; font-size: 12px; color: ${f === "dark" ? "#94a3b8" : "#475569"};">Enter your ${e} token for this publish only. It is not stored.</p>
|
|
@@ -824,27 +879,27 @@ function qe(e, t) {
|
|
|
824
879
|
</div>
|
|
825
880
|
</div>
|
|
826
881
|
`;
|
|
827
|
-
const n =
|
|
828
|
-
const
|
|
829
|
-
if (!
|
|
830
|
-
|
|
882
|
+
const n = r.querySelector("#facms-token-input"), o = r.querySelector("#facms-token-error"), s = () => r.style.display = "none", i = () => {
|
|
883
|
+
const l = (n?.value ?? "").trim();
|
|
884
|
+
if (!l) {
|
|
885
|
+
o && (o.style.display = "block");
|
|
831
886
|
return;
|
|
832
887
|
}
|
|
833
|
-
|
|
888
|
+
o && (o.style.display = "none"), s(), t(l);
|
|
834
889
|
};
|
|
835
|
-
|
|
890
|
+
r.querySelector("#facms-token-cancel")?.addEventListener("click", s), r.querySelector("#facms-token-submit")?.addEventListener("click", i), n?.addEventListener("keydown", (l) => l.key === "Enter" && i()), document.body.appendChild(r), n?.focus();
|
|
836
891
|
}
|
|
837
|
-
function
|
|
838
|
-
const
|
|
839
|
-
|
|
892
|
+
function Ve(e, t, a) {
|
|
893
|
+
const r = document.getElementById(Q);
|
|
894
|
+
r && r.remove();
|
|
840
895
|
const n = document.createElement("div");
|
|
841
|
-
n.id =
|
|
896
|
+
n.id = Q, n.style.position = "fixed", n.style.inset = "0", n.style.zIndex = "2147483647", n.style.background = "rgba(2, 6, 23, 0.45)", n.style.display = "grid", n.style.placeItems = "center", n.innerHTML = `
|
|
842
897
|
<div style="width: min(520px, 92vw); background: ${f === "dark" ? "#0f172a" : "#ffffff"}; color: ${f === "dark" ? "#e2e8f0" : "#0f172a"}; border: 1px solid ${f === "dark" ? "#334155" : "#e2e8f0"}; border-radius: 16px; padding: 16px; box-shadow: 0 20px 55px rgba(2,6,23,0.45); font-family: Inter, system-ui, sans-serif;">
|
|
843
898
|
<h3 style="margin: 0 0 6px 0; font-size: 20px; line-height: 1.2; font-weight: 700;">Add translation</h3>
|
|
844
899
|
<p style="margin: 0 0 8px 0; font-size: 12px; color: ${f === "dark" ? "#94a3b8" : "#475569"};">Pick a supported language or define a custom one for manual translation.</p>
|
|
845
900
|
<select id="facms-language-select" style="width: 100%; border: 1px solid ${f === "dark" ? "#475569" : "#cbd5e1"}; background: ${f === "dark" ? "#1e293b" : "#ffffff"}; color: ${f === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px;">
|
|
846
901
|
<option value="">Select supported language</option>
|
|
847
|
-
${
|
|
902
|
+
${P.filter((d) => !e.includes(d.code)).map((d) => `<option value="${d.code}">${d.label} (${d.code})</option>`).join("")}
|
|
848
903
|
<option value="__custom__">Custom language (manual)</option>
|
|
849
904
|
</select>
|
|
850
905
|
<input id="facms-language-name" type="text" placeholder="Custom language name (e.g. Klingon)" style="width: 100%; border: 1px solid ${f === "dark" ? "#475569" : "#cbd5e1"}; background: ${f === "dark" ? "#1e293b" : "#ffffff"}; color: ${f === "dark" ? "#f1f5f9" : "#0f172a"}; border-radius: 10px; padding: 10px 12px; font-size: 14px; box-sizing: border-box; margin-bottom: 8px; display:none;" />
|
|
@@ -857,27 +912,27 @@ function Ke(e, t, a) {
|
|
|
857
912
|
</div>
|
|
858
913
|
</div>
|
|
859
914
|
`;
|
|
860
|
-
const
|
|
861
|
-
n.querySelector("#facms-language-cancel")?.addEventListener("click",
|
|
862
|
-
const s = n.querySelector("#facms-language-select"), i = n.querySelector("#facms-language-input"),
|
|
915
|
+
const o = () => n.style.display = "none";
|
|
916
|
+
n.querySelector("#facms-language-cancel")?.addEventListener("click", o);
|
|
917
|
+
const s = n.querySelector("#facms-language-select"), i = n.querySelector("#facms-language-input"), l = n.querySelector("#facms-language-name");
|
|
863
918
|
s?.addEventListener("change", () => {
|
|
864
919
|
const d = s.value === "__custom__";
|
|
865
|
-
i && (i.style.display = d ? "block" : "none"),
|
|
920
|
+
i && (i.style.display = d ? "block" : "none"), l && (l.style.display = d ? "block" : "none");
|
|
866
921
|
});
|
|
867
922
|
const u = (d) => {
|
|
868
|
-
const
|
|
923
|
+
const c = n.querySelector("#facms-language-error");
|
|
869
924
|
let p = "";
|
|
870
925
|
const g = s?.value ?? "";
|
|
871
|
-
let
|
|
872
|
-
if (g && g !== "__custom__" ? (p = C(g),
|
|
873
|
-
|
|
926
|
+
let h = "";
|
|
927
|
+
if (g && g !== "__custom__" ? (p = C(g), h = E(p)) : (p = C(i?.value ?? ""), h = (l?.value ?? "").trim()), !p || !/^[a-z]{2,3}([_-][a-z0-9]{2,8})?$|^[a-z]{3}_[A-Za-z]+$/i.test(p)) {
|
|
928
|
+
c && (c.textContent = "Enter a valid language code.", c.style.display = "block");
|
|
874
929
|
return;
|
|
875
930
|
}
|
|
876
|
-
if (
|
|
877
|
-
|
|
931
|
+
if (h || (h = E(p)), e.includes(p)) {
|
|
932
|
+
c && (c.textContent = `Language "${p}" already exists.`, c.style.display = "block");
|
|
878
933
|
return;
|
|
879
934
|
}
|
|
880
|
-
|
|
935
|
+
c && (c.style.display = "none"), o(), a(`${p}::${h}`, d);
|
|
881
936
|
};
|
|
882
937
|
n.querySelector("#facms-language-manual")?.addEventListener("click", () => u("manual")), t && n.querySelector("#facms-language-autofill")?.addEventListener("click", () => u("auto")), document.body.appendChild(n);
|
|
883
938
|
}
|
|
@@ -896,12 +951,12 @@ function H(e) {
|
|
|
896
951
|
return t === "/" ? "/" : (t.startsWith("/") ? t : `/${t}`).toLowerCase();
|
|
897
952
|
}
|
|
898
953
|
function E(e) {
|
|
899
|
-
const t = C(e), a =
|
|
954
|
+
const t = C(e), a = P.find((r) => r.code === t);
|
|
900
955
|
return a ? a.label : t.toUpperCase();
|
|
901
956
|
}
|
|
902
|
-
function
|
|
957
|
+
function Xe() {
|
|
903
958
|
try {
|
|
904
|
-
const e = localStorage.getItem(
|
|
959
|
+
const e = localStorage.getItem(fe);
|
|
905
960
|
if (!e)
|
|
906
961
|
return {};
|
|
907
962
|
const t = JSON.parse(e);
|
|
@@ -911,57 +966,57 @@ function Fe() {
|
|
|
911
966
|
}
|
|
912
967
|
}
|
|
913
968
|
function q(e) {
|
|
914
|
-
localStorage.setItem(
|
|
969
|
+
localStorage.setItem(fe, JSON.stringify(e));
|
|
915
970
|
}
|
|
916
971
|
function j(e) {
|
|
917
|
-
const t = localStorage.getItem(
|
|
972
|
+
const t = localStorage.getItem(ue);
|
|
918
973
|
return t && e[t] ? t : e.en ? "en" : Object.keys(e)[0] ?? "en";
|
|
919
974
|
}
|
|
920
|
-
function
|
|
921
|
-
localStorage.setItem(
|
|
975
|
+
function te(e) {
|
|
976
|
+
localStorage.setItem(ue, e);
|
|
922
977
|
}
|
|
923
|
-
function
|
|
978
|
+
function y(e) {
|
|
924
979
|
return e.replace(/[&<>'"]/g, (t) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[t]);
|
|
925
980
|
}
|
|
926
981
|
function T(e, t = 72) {
|
|
927
982
|
const a = e.replace(/\s+/g, " ").trim();
|
|
928
983
|
return a.length <= t ? a : `${a.slice(0, t)}...`;
|
|
929
984
|
}
|
|
930
|
-
function
|
|
985
|
+
function Ze(e) {
|
|
931
986
|
return e.type === "section" ? T((e.sectionItems ?? []).join(" | ")) : e.type === "property" ? T(JSON.stringify(e.attrs ?? {})) : T(e.value);
|
|
932
987
|
}
|
|
933
|
-
function
|
|
988
|
+
function Qe(e) {
|
|
934
989
|
const t = [];
|
|
935
|
-
return e.forEach((a,
|
|
936
|
-
const n = (a.selector ?? "").trim(),
|
|
937
|
-
if (!!(
|
|
938
|
-
|
|
990
|
+
return e.forEach((a, r) => {
|
|
991
|
+
const n = (a.selector ?? "").trim(), o = t[t.length - 1];
|
|
992
|
+
if (!!(o && n && o.selector === n) && o) {
|
|
993
|
+
o.items.push({ node: a, index: r });
|
|
939
994
|
return;
|
|
940
995
|
}
|
|
941
996
|
t.push({
|
|
942
|
-
key: n || `group_${
|
|
997
|
+
key: n || `group_${r}`,
|
|
943
998
|
selector: n,
|
|
944
|
-
items: [{ node: a, index:
|
|
999
|
+
items: [{ node: a, index: r }]
|
|
945
1000
|
});
|
|
946
1001
|
}), t;
|
|
947
1002
|
}
|
|
948
|
-
function
|
|
1003
|
+
function et(e) {
|
|
949
1004
|
const t = (a) => {
|
|
950
1005
|
if (Array.isArray(a))
|
|
951
1006
|
return a.map(t);
|
|
952
1007
|
if (a && typeof a == "object") {
|
|
953
|
-
const
|
|
954
|
-
return Object.fromEntries(
|
|
1008
|
+
const r = Object.entries(a).sort(([n], [o]) => n.localeCompare(o));
|
|
1009
|
+
return Object.fromEntries(r.map(([n, o]) => [n, t(o)]));
|
|
955
1010
|
}
|
|
956
1011
|
return a;
|
|
957
1012
|
};
|
|
958
1013
|
return JSON.stringify(t(e));
|
|
959
1014
|
}
|
|
960
|
-
async function
|
|
1015
|
+
async function tt(e) {
|
|
961
1016
|
const t = new TextEncoder().encode(e), a = await crypto.subtle.digest("SHA-256", t);
|
|
962
|
-
return Array.from(new Uint8Array(a)).map((
|
|
1017
|
+
return Array.from(new Uint8Array(a)).map((r) => r.toString(16).padStart(2, "0")).join("");
|
|
963
1018
|
}
|
|
964
|
-
function
|
|
1019
|
+
function at(e) {
|
|
965
1020
|
const t = (e ?? "").trim();
|
|
966
1021
|
if (!t)
|
|
967
1022
|
return t;
|
|
@@ -971,143 +1026,143 @@ function Xe(e) {
|
|
|
971
1026
|
}
|
|
972
1027
|
return t.replace(/^\.?\//, "");
|
|
973
1028
|
}
|
|
974
|
-
async function
|
|
975
|
-
const
|
|
976
|
-
(i) => i.sourceRefs.map((
|
|
1029
|
+
async function nt(e, t, a) {
|
|
1030
|
+
const r = /* @__PURE__ */ new Set(), n = e.nodes.flatMap(
|
|
1031
|
+
(i) => i.sourceRefs.map((l) => ({
|
|
977
1032
|
file: (() => {
|
|
978
|
-
const u = (
|
|
1033
|
+
const u = (l.file ?? "").trim();
|
|
979
1034
|
if (u.startsWith("/")) {
|
|
980
1035
|
const d = H(u);
|
|
981
1036
|
if (!U[d])
|
|
982
|
-
return
|
|
1037
|
+
return r.add(d), u;
|
|
983
1038
|
}
|
|
984
|
-
return
|
|
1039
|
+
return at(u);
|
|
985
1040
|
})(),
|
|
986
|
-
find:
|
|
1041
|
+
find: l.original,
|
|
987
1042
|
replace: i.type === "property" ? JSON.stringify(i.attrs ?? {}) : i.type === "section" ? (i.sectionItems ?? []).join(" ") : (i.type === "text", i.value),
|
|
988
|
-
occurrence:
|
|
1043
|
+
occurrence: l.occurrence ?? 1
|
|
989
1044
|
}))
|
|
990
1045
|
);
|
|
991
|
-
if (
|
|
1046
|
+
if (r.size)
|
|
992
1047
|
throw new Error(
|
|
993
|
-
`Missing route mappings for: ${Array.from(
|
|
1048
|
+
`Missing route mappings for: ${Array.from(r).join(", ")}. Run setup again and commit public/cms-route-map.json.`
|
|
994
1049
|
);
|
|
995
|
-
const
|
|
1050
|
+
const o = {
|
|
996
1051
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
997
1052
|
content: { ...e, updatedAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
998
1053
|
operations: n,
|
|
999
1054
|
locales: t
|
|
1000
|
-
}, s = await
|
|
1055
|
+
}, s = await tt(et(o));
|
|
1001
1056
|
return {
|
|
1002
|
-
...
|
|
1057
|
+
...o,
|
|
1003
1058
|
integrity: {
|
|
1004
1059
|
algorithm: "sha256",
|
|
1005
1060
|
value: s
|
|
1006
1061
|
}
|
|
1007
1062
|
};
|
|
1008
1063
|
}
|
|
1009
|
-
function
|
|
1010
|
-
const a = `${e.type.toUpperCase()} • ${
|
|
1064
|
+
function rt(e, t) {
|
|
1065
|
+
const a = `${e.type.toUpperCase()} • ${y(e.label || e.selector || "")}`, r = `<div class="text-xs text-slate-500 dark:text-slate-400 mb-2">#${t + 1} ${a}</div>`;
|
|
1011
1066
|
if (e.type === "text")
|
|
1012
|
-
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${
|
|
1067
|
+
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="value" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-24 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(e.value)}</textarea></div>`;
|
|
1013
1068
|
if (e.type === "image" || e.type === "video")
|
|
1014
|
-
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${
|
|
1069
|
+
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<label class="text-xs text-slate-500 dark:text-slate-400">Source URL</label><input data-cms-id="${e.id}" data-cms-field="value" value="${y(e.value)}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm mb-2 focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /><label class="text-xs text-slate-500 dark:text-slate-400">Alt text</label><input data-cms-id="${e.id}" data-cms-field="alt" value="${y(e.attrs?.alt ?? "")}" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/40" /></div>`;
|
|
1015
1070
|
if (e.type === "section") {
|
|
1016
1071
|
const n = (e.sectionItems ?? []).join(`
|
|
1017
1072
|
`);
|
|
1018
|
-
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${
|
|
1073
|
+
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="sectionItems" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-sm h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(n)}</textarea></div>`;
|
|
1019
1074
|
}
|
|
1020
|
-
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${
|
|
1075
|
+
return `<div class="rounded-lg p-2 bg-slate-50/60 dark:bg-slate-900/40">${r}<textarea data-cms-id="${e.id}" data-cms-field="attrs" class="w-full border border-slate-300 dark:border-slate-800 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 rounded-lg p-2 text-xs h-28 focus:outline-none focus:ring-2 focus:ring-indigo-500/40">${y(JSON.stringify(e.attrs ?? {}, null, 2))}</textarea></div>`;
|
|
1021
1076
|
}
|
|
1022
|
-
function _(e, t, a,
|
|
1077
|
+
function _(e, t, a, r) {
|
|
1023
1078
|
e.nodes.forEach((n) => {
|
|
1024
|
-
n.type === "text" && (n.value = t[n.key] ??
|
|
1079
|
+
n.type === "text" && (n.value = t[n.key] ?? r[n.key] ?? n.value, B(n, a));
|
|
1025
1080
|
});
|
|
1026
1081
|
}
|
|
1027
|
-
function
|
|
1082
|
+
function ot(e, t) {
|
|
1028
1083
|
e.activeLanguage = t;
|
|
1029
1084
|
const a = e.locales[t] ?? e.locales[e.mainLanguage] ?? e.baseTextByKey;
|
|
1030
1085
|
_(e.content, a, e.workingDocument, e.baseTextByKey);
|
|
1031
1086
|
}
|
|
1032
|
-
function
|
|
1087
|
+
function st(e, t) {
|
|
1033
1088
|
const a = e.querySelector("#facms-language-tabs");
|
|
1034
1089
|
if (!a)
|
|
1035
1090
|
return;
|
|
1036
|
-
const
|
|
1037
|
-
a.innerHTML =
|
|
1038
|
-
const
|
|
1039
|
-
return `<div class="inline-flex items-center rounded-lg overflow-hidden border ${
|
|
1040
|
-
<button data-lang="${n}" class="px-2.5 py-1.5 text-xs ${
|
|
1041
|
-
${s ? `<span class="px-2 py-1.5 text-[10px] font-semibold ${
|
|
1042
|
-
<button data-remove-lang="${n}" title="Remove language" class="px-2 py-1.5 text-xs ${
|
|
1091
|
+
const r = Object.keys(t.locales);
|
|
1092
|
+
a.innerHTML = r.map((n) => {
|
|
1093
|
+
const o = n === t.activeLanguage, s = n === t.mainLanguage, i = t.languageLabels[n] ?? E(n);
|
|
1094
|
+
return `<div class="inline-flex items-center rounded-lg overflow-hidden border ${o ? "border-indigo-500" : "border-slate-200 dark:border-slate-700"}">
|
|
1095
|
+
<button data-lang="${n}" class="px-2.5 py-1.5 text-xs ${o ? "bg-indigo-600 text-white" : "bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-200"}">${y(i)}</button>
|
|
1096
|
+
${s ? `<span class="px-2 py-1.5 text-[10px] font-semibold ${o ? "bg-indigo-700 text-indigo-100" : "bg-emerald-600 text-white"}">MAIN</span>` : `<button data-main-lang="${n}" title="Set as main language" class="px-2 py-1.5 text-xs ${o ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-emerald-600 text-white hover:bg-emerald-500"}">★</button>`}
|
|
1097
|
+
<button data-remove-lang="${n}" title="Remove language" class="px-2 py-1.5 text-xs ${o ? "bg-indigo-700 text-indigo-100 hover:bg-indigo-800" : "bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-300 dark:hover:bg-slate-600"}">×</button>
|
|
1043
1098
|
</div>`;
|
|
1044
1099
|
}).join(""), a.querySelectorAll("[data-lang]").forEach((n) => {
|
|
1045
1100
|
n.addEventListener("click", () => {
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1101
|
+
const o = n.dataset.lang;
|
|
1102
|
+
o && (ot(t, o), $(e, t));
|
|
1048
1103
|
});
|
|
1049
1104
|
}), a.querySelectorAll("[data-main-lang]").forEach((n) => {
|
|
1050
|
-
n.addEventListener("click", (
|
|
1051
|
-
|
|
1105
|
+
n.addEventListener("click", (o) => {
|
|
1106
|
+
o.stopPropagation();
|
|
1052
1107
|
const s = n.dataset.mainLang;
|
|
1053
|
-
!s || !t.locales[s] || (t.mainLanguage = s,
|
|
1108
|
+
!s || !t.locales[s] || (t.mainLanguage = s, te(s), t.baseTextByKey = { ...t.locales[s] }, $(e, t));
|
|
1054
1109
|
});
|
|
1055
1110
|
}), a.querySelectorAll("[data-remove-lang]").forEach((n) => {
|
|
1056
|
-
n.addEventListener("click", (
|
|
1057
|
-
|
|
1111
|
+
n.addEventListener("click", (o) => {
|
|
1112
|
+
o.stopPropagation();
|
|
1058
1113
|
const s = n.dataset.removeLang;
|
|
1059
1114
|
if (s) {
|
|
1060
1115
|
if (Object.keys(t.locales).length <= 1) {
|
|
1061
1116
|
alert("You must keep at least one language.");
|
|
1062
1117
|
return;
|
|
1063
1118
|
}
|
|
1064
|
-
delete t.locales[s], delete t.languageLabels[s], q(t.languageLabels), I(t.locales), t.mainLanguage === s && (t.mainLanguage = j(t.locales),
|
|
1119
|
+
delete t.locales[s], delete t.languageLabels[s], q(t.languageLabels), I(t.locales), t.mainLanguage === s && (t.mainLanguage = j(t.locales), te(t.mainLanguage), t.baseTextByKey = { ...t.locales[t.mainLanguage] ?? {} }), t.activeLanguage === s && (t.activeLanguage = K(t.locales, t.mainLanguage)), xe(t), $(e, t);
|
|
1065
1120
|
}
|
|
1066
1121
|
});
|
|
1067
1122
|
});
|
|
1068
1123
|
}
|
|
1069
|
-
function
|
|
1124
|
+
function it(e, t) {
|
|
1070
1125
|
e.querySelectorAll("[data-cms-id]").forEach((a) => {
|
|
1071
|
-
const
|
|
1072
|
-
!
|
|
1073
|
-
const
|
|
1074
|
-
if (
|
|
1126
|
+
const r = a.dataset.cmsId, n = a.dataset.cmsField;
|
|
1127
|
+
!r || !n || a.addEventListener("input", () => {
|
|
1128
|
+
const o = t.content.nodes.find((s) => s.id === r);
|
|
1129
|
+
if (o) {
|
|
1075
1130
|
if (n === "value")
|
|
1076
|
-
|
|
1131
|
+
o.value = a.value, o.type === "text" && (t.activeLanguage === t.mainLanguage ? (t.baseTextByKey[o.key] = a.value, t.locales[t.mainLanguage] = { ...t.locales[t.mainLanguage] ?? {}, [o.key]: a.value }) : t.locales[t.activeLanguage] = {
|
|
1077
1132
|
...t.locales[t.activeLanguage] ?? {},
|
|
1078
|
-
[
|
|
1133
|
+
[o.key]: a.value
|
|
1079
1134
|
}, I(t.locales));
|
|
1080
|
-
else if (n === "alt")
|
|
1081
|
-
else if (n === "sectionItems")
|
|
1135
|
+
else if (n === "alt") o.attrs = { ...o.attrs ?? {}, alt: a.value };
|
|
1136
|
+
else if (n === "sectionItems") o.sectionItems = a.value.split(`
|
|
1082
1137
|
`).map((s) => s.trim()).filter(Boolean);
|
|
1083
1138
|
else if (n === "attrs")
|
|
1084
1139
|
try {
|
|
1085
|
-
|
|
1140
|
+
o.attrs = JSON.parse(a.value);
|
|
1086
1141
|
} catch {
|
|
1087
1142
|
return;
|
|
1088
1143
|
}
|
|
1089
|
-
|
|
1144
|
+
B(o, t.workingDocument), oe(t.content);
|
|
1090
1145
|
}
|
|
1091
1146
|
});
|
|
1092
1147
|
});
|
|
1093
1148
|
}
|
|
1094
|
-
function
|
|
1095
|
-
const
|
|
1096
|
-
R(a, t),
|
|
1149
|
+
function k(e, t, a) {
|
|
1150
|
+
const r = e.querySelector("#facms-i18n-status"), n = e.querySelector("#facms-translate-loader"), o = e.querySelector("#facms-add-language");
|
|
1151
|
+
R(a, t), r && (r.textContent = t), n && (n.style.display = a ? "inline-flex" : "none"), o && (o.disabled = a);
|
|
1097
1152
|
}
|
|
1098
1153
|
function R(e, t) {
|
|
1099
|
-
const a = document.getElementById("facms-global-loader"),
|
|
1100
|
-
a && (a.style.display = e ? "flex" : "none"),
|
|
1154
|
+
const a = document.getElementById("facms-global-loader"), r = document.getElementById("facms-global-loader-label");
|
|
1155
|
+
a && (a.style.display = e ? "flex" : "none"), r && (r.textContent = e ? t : "Loading");
|
|
1101
1156
|
}
|
|
1102
|
-
function
|
|
1103
|
-
const a =
|
|
1104
|
-
const
|
|
1157
|
+
function $(e, t) {
|
|
1158
|
+
const a = Qe(t.content.nodes), r = a.length ? a.map((n) => {
|
|
1159
|
+
const o = n.items[0], s = n.items[n.items.length - 1], i = o.index === s.index ? `#${o.index + 1}` : `#${o.index + 1} - #${s.index + 1}`, l = n.items.map((c) => Ze(c.node)).filter(Boolean).join(" • "), u = n.items.length > 1 ? `${i} ${y(n.selector || "Grouped fields")} (${n.items.length} fields)` : `${i} ${y(o.node.type.toUpperCase())} • ${y(o.node.label || o.node.selector || "")}`, d = n.items.map((c) => rt(c.node, c.index)).join("");
|
|
1105
1160
|
return `
|
|
1106
1161
|
<details class="rounded-xl p-2 border border-slate-200 dark:border-transparent bg-white dark:bg-slate-900/60 shadow-sm">
|
|
1107
1162
|
<summary class="list-none cursor-pointer flex items-center justify-between gap-2 p-3 rounded-lg bg-slate-50 dark:bg-slate-800/70 border border-slate-200 dark:border-slate-800">
|
|
1108
1163
|
<div class="min-w-0">
|
|
1109
1164
|
<div class="text-xs text-slate-500 dark:text-slate-400">${u}</div>
|
|
1110
|
-
<div class="text-sm text-slate-700 dark:text-slate-300 truncate">${
|
|
1165
|
+
<div class="text-sm text-slate-700 dark:text-slate-300 truncate">${y(T(l || "No preview"))}</div>
|
|
1111
1166
|
</div>
|
|
1112
1167
|
<span class="text-xs text-indigo-600 dark:text-indigo-400">Expand</span>
|
|
1113
1168
|
</summary>
|
|
@@ -1124,7 +1179,7 @@ function L(e, t) {
|
|
|
1124
1179
|
<div id="facms-language-tabs" class="flex flex-wrap gap-2"></div>
|
|
1125
1180
|
<button id="facms-add-language" class="px-2.5 py-1.5 rounded-lg text-xs border border-indigo-500 text-indigo-600 dark:text-indigo-300 dark:border-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-900/30">+ Add translation</button>
|
|
1126
1181
|
</div>
|
|
1127
|
-
<div class="space-y-3">${
|
|
1182
|
+
<div class="space-y-3">${r}</div>
|
|
1128
1183
|
<div class="mt-4 flex flex-wrap gap-2">
|
|
1129
1184
|
<button id="facms-save" class="px-3 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-500 shadow">Save + Publish</button>
|
|
1130
1185
|
</div>
|
|
@@ -1133,149 +1188,149 @@ function L(e, t) {
|
|
|
1133
1188
|
<p id="facms-i18n-status" class="text-xs text-slate-500 dark:text-slate-400"></p>
|
|
1134
1189
|
</div>
|
|
1135
1190
|
</div>
|
|
1136
|
-
`,
|
|
1137
|
-
let n,
|
|
1191
|
+
`, st(e, t), e.querySelector("#facms-save")?.addEventListener("click", async () => {
|
|
1192
|
+
let n, o;
|
|
1138
1193
|
try {
|
|
1139
|
-
n = await
|
|
1194
|
+
n = await nt(t.content, t.locales, t.baseTextByKey), o = await Ie();
|
|
1140
1195
|
} catch (i) {
|
|
1141
|
-
const
|
|
1142
|
-
alert(`Could not prepare publish payload: ${
|
|
1196
|
+
const l = i instanceof Error ? i.message : String(i);
|
|
1197
|
+
alert(`Could not prepare publish payload: ${l}`);
|
|
1143
1198
|
return;
|
|
1144
1199
|
}
|
|
1145
|
-
if (!
|
|
1200
|
+
if (!o || o.provider === "none") {
|
|
1146
1201
|
Le(n), alert("Patch downloaded. Configure hosting in setup for one-click publish.");
|
|
1147
1202
|
return;
|
|
1148
1203
|
}
|
|
1149
|
-
const s =
|
|
1150
|
-
|
|
1151
|
-
let
|
|
1204
|
+
const s = o.provider;
|
|
1205
|
+
Ye(s, async (i) => {
|
|
1206
|
+
let l = !1, u = "Publishing failed. Please verify token permissions and repository settings.";
|
|
1152
1207
|
try {
|
|
1153
|
-
|
|
1208
|
+
l = await Ge(n, i, o);
|
|
1154
1209
|
} catch (d) {
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1210
|
+
const c = d instanceof Error ? d.message : String(d);
|
|
1211
|
+
c && (u = `Publishing failed: ${c}`), l = !1;
|
|
1157
1212
|
}
|
|
1158
|
-
if (!
|
|
1213
|
+
if (!l) {
|
|
1159
1214
|
alert(u);
|
|
1160
1215
|
return;
|
|
1161
1216
|
}
|
|
1162
1217
|
alert("Changes published successfully.");
|
|
1163
1218
|
});
|
|
1164
1219
|
}), e.querySelector("#facms-add-language")?.addEventListener("click", () => {
|
|
1165
|
-
|
|
1166
|
-
const [s, i] = n.split("::"),
|
|
1167
|
-
if (!
|
|
1220
|
+
Ve(Object.keys(t.locales), x?.autoTranslateEnabled ?? !0, async (n, o) => {
|
|
1221
|
+
const [s, i] = n.split("::"), l = C(s ?? ""), u = (i ?? "").trim() || E(l);
|
|
1222
|
+
if (!l)
|
|
1168
1223
|
return;
|
|
1169
|
-
const d = performance.now(),
|
|
1224
|
+
const d = performance.now(), c = t.locales[t.mainLanguage] ?? t.baseTextByKey, p = { ...c };
|
|
1170
1225
|
if (z("Add language requested", {
|
|
1171
|
-
lang:
|
|
1172
|
-
mode:
|
|
1173
|
-
sourceKeys: Object.keys(
|
|
1226
|
+
lang: l,
|
|
1227
|
+
mode: o,
|
|
1228
|
+
sourceKeys: Object.keys(c).length,
|
|
1174
1229
|
browserLanguage: navigator.language,
|
|
1175
1230
|
browserLanguages: navigator.languages
|
|
1176
|
-
}), t.locales[
|
|
1177
|
-
|
|
1231
|
+
}), t.locales[l] = p, t.languageLabels[l] = u, q(t.languageLabels), t.activeLanguage = l, I(t.locales), _(t.content, t.locales[l], t.workingDocument, t.baseTextByKey), $(e, t), z("Manual language tab created", { lang: l }), k(e, `Added ${u} tab prefilled with source text for manual translation.`, !1), o !== "auto" || !(x?.autoTranslateEnabled ?? !0)) {
|
|
1232
|
+
o === "auto" && !(x?.autoTranslateEnabled ?? !0) && k(e, `Privacy mode is on. Added ${u} tab for manual translation only.`, !1);
|
|
1178
1233
|
return;
|
|
1179
1234
|
}
|
|
1180
1235
|
try {
|
|
1181
|
-
const g = Object.keys(
|
|
1182
|
-
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1236
|
+
const g = Object.keys(c).length;
|
|
1237
|
+
k(e, `Auto-filling ${u} translation... (0/${g})`, !0);
|
|
1238
|
+
const h = await Ae(c, l, t.mainLanguage, (F, b) => {
|
|
1239
|
+
k(e, `Auto-filling ${u} translation... (${F}/${b})`, !0);
|
|
1185
1240
|
});
|
|
1186
|
-
t.locales[
|
|
1187
|
-
lang:
|
|
1188
|
-
translatedKeys: Object.keys(
|
|
1241
|
+
t.locales[l] = h, I(t.locales), t.activeLanguage = l, _(t.content, h, t.workingDocument, t.baseTextByKey), $(e, t), z("Automatic translation succeeded", {
|
|
1242
|
+
lang: l,
|
|
1243
|
+
translatedKeys: Object.keys(h).length,
|
|
1189
1244
|
ms: Math.round(performance.now() - d)
|
|
1190
|
-
}),
|
|
1245
|
+
}), k(e, `Added ${u} with auto-filled translation. Review and edit as needed.`, !1);
|
|
1191
1246
|
} catch (g) {
|
|
1192
1247
|
console.error("[frontend-auto-cms:dashboard] Automatic translation failed", {
|
|
1193
|
-
lang:
|
|
1248
|
+
lang: l,
|
|
1194
1249
|
message: g instanceof Error ? g.message : String(g),
|
|
1195
1250
|
stack: g instanceof Error ? g.stack : void 0,
|
|
1196
1251
|
ms: Math.round(performance.now() - d)
|
|
1197
|
-
}),
|
|
1252
|
+
}), k(e, `Auto-fill failed. ${u} stays prefilled with source text for manual editing.`, !1);
|
|
1198
1253
|
}
|
|
1199
1254
|
});
|
|
1200
|
-
}),
|
|
1255
|
+
}), it(e, t);
|
|
1201
1256
|
}
|
|
1202
1257
|
function K(e, t) {
|
|
1203
|
-
const a = Object.keys(e),
|
|
1204
|
-
for (const
|
|
1205
|
-
if (a.includes(
|
|
1206
|
-
return
|
|
1207
|
-
return a.includes(
|
|
1258
|
+
const a = Object.keys(e), r = t && e[t] ? t : j(e), n = [...navigator.languages ?? [], navigator.language].map((o) => o.toLowerCase().split("-")[0]);
|
|
1259
|
+
for (const o of n)
|
|
1260
|
+
if (a.includes(o))
|
|
1261
|
+
return o;
|
|
1262
|
+
return a.includes(r) ? r : a[0] ?? "en";
|
|
1208
1263
|
}
|
|
1209
|
-
function
|
|
1264
|
+
function xe(e) {
|
|
1210
1265
|
const t = e.locales[e.activeLanguage] ?? e.locales.en ?? e.baseTextByKey;
|
|
1211
1266
|
_(e.content, t, e.workingDocument, e.baseTextByKey);
|
|
1212
1267
|
}
|
|
1213
|
-
function
|
|
1268
|
+
function lt(e) {
|
|
1214
1269
|
return new Promise((t) => window.setTimeout(t, e));
|
|
1215
1270
|
}
|
|
1216
|
-
async function
|
|
1271
|
+
async function ae(e, t) {
|
|
1217
1272
|
const a = [0, 120, 280, 600, 1100, 1800, 2600];
|
|
1218
|
-
let
|
|
1219
|
-
if (
|
|
1220
|
-
return
|
|
1273
|
+
let r = S(e, t);
|
|
1274
|
+
if (r.nodes.length > 0)
|
|
1275
|
+
return r;
|
|
1221
1276
|
for (const n of a.slice(1))
|
|
1222
|
-
if (await
|
|
1223
|
-
return
|
|
1224
|
-
return
|
|
1277
|
+
if (await lt(n), r = S(e, t), r.nodes.length > 0)
|
|
1278
|
+
return r;
|
|
1279
|
+
return r;
|
|
1225
1280
|
}
|
|
1226
|
-
function
|
|
1227
|
-
const
|
|
1281
|
+
function ct(e, t, a) {
|
|
1282
|
+
const r = se(), n = {
|
|
1228
1283
|
...a,
|
|
1229
|
-
...
|
|
1230
|
-
},
|
|
1284
|
+
...r
|
|
1285
|
+
}, o = Xe(), s = Object.fromEntries(e.nodes.filter((c) => c.type === "text").map((c) => [c.key, c.value])), i = j(n), l = {
|
|
1231
1286
|
...n,
|
|
1232
1287
|
[i]: { ...n[i] ?? {}, ...s }
|
|
1233
1288
|
};
|
|
1234
|
-
!
|
|
1235
|
-
const u = K(
|
|
1236
|
-
return Object.keys(
|
|
1237
|
-
d[
|
|
1289
|
+
!l.en && i === "en" && (l.en = Object.assign({}, l.en ?? {}, s));
|
|
1290
|
+
const u = K(l, i), d = { ...o };
|
|
1291
|
+
return Object.keys(l).forEach((c) => {
|
|
1292
|
+
d[c] || (d[c] = E(c));
|
|
1238
1293
|
}), q(d), {
|
|
1239
1294
|
content: e,
|
|
1240
|
-
locales:
|
|
1295
|
+
locales: l,
|
|
1241
1296
|
workingDocument: t,
|
|
1242
|
-
baseTextByKey:
|
|
1297
|
+
baseTextByKey: l[i] ?? s,
|
|
1243
1298
|
activeLanguage: u,
|
|
1244
1299
|
mainLanguage: i,
|
|
1245
1300
|
languageLabels: d
|
|
1246
1301
|
};
|
|
1247
1302
|
}
|
|
1248
|
-
async function
|
|
1303
|
+
async function dt() {
|
|
1249
1304
|
const e = await ke();
|
|
1250
1305
|
if (!e?.nodes?.length)
|
|
1251
1306
|
return;
|
|
1252
1307
|
const t = S(document, location.pathname);
|
|
1253
1308
|
if (!t.nodes.length)
|
|
1254
1309
|
return;
|
|
1255
|
-
const a = new Map(e.nodes.map((
|
|
1256
|
-
t.nodes.forEach((
|
|
1257
|
-
const n = a.get(
|
|
1258
|
-
!n || n.type !==
|
|
1310
|
+
const a = new Map(e.nodes.map((r) => [r.key, r]));
|
|
1311
|
+
t.nodes.forEach((r) => {
|
|
1312
|
+
const n = a.get(r.key);
|
|
1313
|
+
!n || n.type !== r.type || (r.value = n.value, n.attrs && (r.attrs = { ...n.attrs }), n.sectionItems && (r.sectionItems = [...n.sectionItems]), B(r, document));
|
|
1259
1314
|
});
|
|
1260
1315
|
}
|
|
1261
|
-
async function
|
|
1262
|
-
await
|
|
1316
|
+
async function ut() {
|
|
1317
|
+
await dt();
|
|
1263
1318
|
const t = {
|
|
1264
|
-
...await
|
|
1265
|
-
...
|
|
1319
|
+
...await ie(),
|
|
1320
|
+
...se()
|
|
1266
1321
|
};
|
|
1267
1322
|
if (!Object.keys(t).length)
|
|
1268
1323
|
return;
|
|
1269
|
-
const a = j(t),
|
|
1270
|
-
if (!
|
|
1324
|
+
const a = j(t), r = K(t, a);
|
|
1325
|
+
if (!r || r === a)
|
|
1271
1326
|
return;
|
|
1272
|
-
const n = S(document, location.pathname),
|
|
1273
|
-
if (!
|
|
1327
|
+
const n = S(document, location.pathname), o = t[r];
|
|
1328
|
+
if (!o)
|
|
1274
1329
|
return;
|
|
1275
1330
|
const s = Object.fromEntries(n.nodes.filter((i) => i.type === "text").map((i) => [i.key, i.value]));
|
|
1276
|
-
_(n,
|
|
1331
|
+
_(n, o, document, s);
|
|
1277
1332
|
}
|
|
1278
|
-
function
|
|
1333
|
+
function ft(e) {
|
|
1279
1334
|
const t = e.pages.length ? e.pages : ["/"];
|
|
1280
1335
|
document.documentElement.style.margin = "0", document.documentElement.style.padding = "0", document.documentElement.style.background = f === "dark" ? "#020617" : "#f1f5f9", document.body.style.margin = "0", document.body.style.padding = "0", document.body.style.background = f === "dark" ? "#020617" : "#f1f5f9", document.body.innerHTML = `
|
|
1281
1336
|
<div id="facms-app" class="h-screen w-screen grid grid-cols-1 lg:grid-cols-[760px_1fr] bg-slate-100 dark:bg-slate-950 text-slate-900 dark:text-slate-100">
|
|
@@ -1305,67 +1360,67 @@ function it(e) {
|
|
|
1305
1360
|
</div>
|
|
1306
1361
|
</div>
|
|
1307
1362
|
`;
|
|
1308
|
-
const a = document.getElementById("facms-route-preview"),
|
|
1363
|
+
const a = document.getElementById("facms-route-preview"), r = document.getElementById("facms-route-editor"), n = document.getElementById("facms-page-tabs"), o = /* @__PURE__ */ new Map();
|
|
1309
1364
|
let s = t[0], i = {};
|
|
1310
|
-
const
|
|
1365
|
+
const l = () => {
|
|
1311
1366
|
n.innerHTML = t.map(
|
|
1312
|
-
(u) => `<button data-page="${u}" class="w-full text-left px-3 py-2 rounded-lg text-sm border ${u === s ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-100 border-slate-200 dark:bg-slate-800 dark:border-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-200 dark:hover:bg-slate-700"}">${
|
|
1367
|
+
(u) => `<button data-page="${u}" class="w-full text-left px-3 py-2 rounded-lg text-sm border ${u === s ? "bg-indigo-600 border-indigo-500 text-white" : "bg-slate-100 border-slate-200 dark:bg-slate-800 dark:border-slate-700 text-slate-700 dark:text-slate-200 hover:bg-slate-200 dark:hover:bg-slate-700"}">${y(u)}</button>`
|
|
1313
1368
|
).join(""), n.querySelectorAll("[data-page]").forEach((u) => {
|
|
1314
1369
|
u.addEventListener("click", () => {
|
|
1315
|
-
s = u.dataset.page || "/",
|
|
1370
|
+
s = u.dataset.page || "/", l(), a.src = s;
|
|
1316
1371
|
});
|
|
1317
1372
|
});
|
|
1318
1373
|
};
|
|
1319
|
-
|
|
1374
|
+
ge(f), a.addEventListener("load", async () => {
|
|
1320
1375
|
const u = a.contentDocument;
|
|
1321
1376
|
if (u) {
|
|
1322
1377
|
R(!0, `Scanning page content for ${s}...`);
|
|
1323
1378
|
try {
|
|
1324
|
-
let d =
|
|
1379
|
+
let d = o.get(s);
|
|
1325
1380
|
if (d) {
|
|
1326
1381
|
d.workingDocument = u;
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1382
|
+
const c = d.content.nodes.length ? S(u, s) : await ae(u, s);
|
|
1383
|
+
c.nodes.length && !d.content.nodes.length && (d.content = c);
|
|
1329
1384
|
} else {
|
|
1330
|
-
const
|
|
1331
|
-
d =
|
|
1385
|
+
const c = await ae(u, s);
|
|
1386
|
+
d = ct(c, u, i), o.set(s, d);
|
|
1332
1387
|
}
|
|
1333
|
-
|
|
1388
|
+
xe(d), oe(d.content), $(r, d);
|
|
1334
1389
|
} finally {
|
|
1335
1390
|
R(!1, "Loading");
|
|
1336
1391
|
}
|
|
1337
1392
|
}
|
|
1338
|
-
}),
|
|
1393
|
+
}), l(), Promise.all([ie(), $e()]).then(([u, d]) => {
|
|
1339
1394
|
i = u, U = d, a.src = s;
|
|
1340
1395
|
});
|
|
1341
1396
|
}
|
|
1342
|
-
async function
|
|
1343
|
-
if (
|
|
1397
|
+
async function ne() {
|
|
1398
|
+
if (pe(), be(), !await he())
|
|
1344
1399
|
return;
|
|
1345
|
-
const e = await
|
|
1400
|
+
const e = await me(), t = () => ft(e);
|
|
1346
1401
|
if (!D) {
|
|
1347
|
-
|
|
1402
|
+
ye(t);
|
|
1348
1403
|
return;
|
|
1349
1404
|
}
|
|
1350
1405
|
t();
|
|
1351
1406
|
}
|
|
1352
|
-
async function
|
|
1353
|
-
const e = await
|
|
1407
|
+
async function pt() {
|
|
1408
|
+
const e = await me(), a = new URLSearchParams(location.search).get("__facms") === "1";
|
|
1354
1409
|
if (location.pathname !== e.dashboardPath && !a) {
|
|
1355
|
-
|
|
1410
|
+
ut();
|
|
1356
1411
|
return;
|
|
1357
1412
|
}
|
|
1358
|
-
if (
|
|
1413
|
+
if (pe(), be(), !!await he()) {
|
|
1359
1414
|
if (!D) {
|
|
1360
|
-
|
|
1361
|
-
|
|
1415
|
+
ye(() => {
|
|
1416
|
+
ne();
|
|
1362
1417
|
});
|
|
1363
1418
|
return;
|
|
1364
1419
|
}
|
|
1365
|
-
|
|
1420
|
+
ne();
|
|
1366
1421
|
}
|
|
1367
1422
|
}
|
|
1368
1423
|
export {
|
|
1369
|
-
|
|
1370
|
-
|
|
1424
|
+
ne as launchDashboard,
|
|
1425
|
+
pt as registerCmsLauncher
|
|
1371
1426
|
};
|