@preprio/toolkit 0.5.0-rc.10 → 0.5.0-rc.12
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/README.md +21 -0
- package/dist/astro/index.cjs +31 -2
- package/dist/astro/index.js +31 -2
- package/dist/{chunk-KD3GK6TO.js → chunk-CABGJW5X.js} +30 -1
- package/dist/{chunk-URXSDJOU.js → chunk-H3AFUPYD.js} +9 -0
- package/dist/{chunk-F46GJS6Y.js → chunk-HVTNUCF7.js} +1 -1
- package/dist/{chunk-IPMB32AZ.js → chunk-LWUSRWFE.js} +2 -2
- package/dist/{chunk-IDEC77LZ.js → chunk-M7FT7XXV.js} +93 -20
- package/dist/{chunk-TBBU3LDD.js → chunk-TJ7VALNA.js} +1 -1
- package/dist/index.cjs +131 -20
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -6
- package/dist/{live-preview-DLXGXRE5.js → live-preview-SFBGATWC.js} +3 -3
- package/dist/nextjs/components.cjs +101 -19
- package/dist/nextjs/components.js +3 -3
- package/dist/nextjs/index.cjs +31 -2
- package/dist/nextjs/index.js +31 -2
- package/dist/nextjs/live-action.js +3 -3
- package/dist/nextjs/live.cjs +30 -1
- package/dist/nextjs/live.js +1 -1
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/nuxt/{live-preview-2RCU35W5.js → live-preview-XMQQZHMZ.js} +30 -1
- package/dist/nuxt/live.cjs +30 -1
- package/dist/nuxt/live.js +1 -1
- package/dist/react/components.cjs +101 -19
- package/dist/react/components.js +101 -19
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/{live-preview-2RCU35W5.js → live-preview-XMQQZHMZ.js} +30 -1
- package/dist/sveltekit/live.cjs +30 -1
- package/dist/sveltekit/live.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -840,6 +840,13 @@ The rest is about rendering:
|
|
|
840
840
|
- Prepr images are click-to-edit inside the editor without any markup: the
|
|
841
841
|
toolkit matches image URLs (also through image optimizers like
|
|
842
842
|
`/_next/image`) to the open item's assets.
|
|
843
|
+
- **A removed image stays until the editor picks another or saves.** The
|
|
844
|
+
page keeps rendering it, faded to 20% opacity, so the layout does not
|
|
845
|
+
shift while the editor chooses a replacement. It stays click-to-edit and
|
|
846
|
+
opens its field. A newly picked image replaces it; after a save the page
|
|
847
|
+
renders stored content, so an empty state you render for a missing image
|
|
848
|
+
shows only then. In a field with several images, a removed one keeps its
|
|
849
|
+
place when the query selects the assets' `_id`.
|
|
843
850
|
- **Set the attributes yourself only where that does not reach:**
|
|
844
851
|
- Data you fetch in the browser without those helpers: run it through
|
|
845
852
|
`annotateEditLinks(result, query)` from `@preprio/toolkit`, or mark the
|
|
@@ -872,6 +879,20 @@ The rest is about rendering:
|
|
|
872
879
|
`data-prepr-reference="<linked item _id>"`. The editor only knows the items
|
|
873
880
|
the open item links to directly; content inside the wrapper is outlined as
|
|
874
881
|
that linked item, and clicking it opens the link in the editor.
|
|
882
|
+
- Content of items the open item does not link to (for example news cards
|
|
883
|
+
filled by a query) is outlined muted as "other item". Clicking it does not
|
|
884
|
+
follow its link: the editor offers to open that item, or to go to the
|
|
885
|
+
linked page. Ctrl/Cmd/Shift-click still opens the link in a new tab, and
|
|
886
|
+
Alt-click follows it. Inside the site's header, footer and navigation
|
|
887
|
+
(`header`, `footer`, `nav` and the `banner`, `contentinfo` and
|
|
888
|
+
`navigation` roles) such content stays unmarked and its links behave as
|
|
889
|
+
any other page link (a `header` or `footer` inside an `article`, `section`,
|
|
890
|
+
`aside` or `main` belongs to that content and is not site chrome). Change
|
|
891
|
+
that per part of the page with an attribute on
|
|
892
|
+
an ancestor; the nearest one wins:
|
|
893
|
+
- `data-prepr-other-item="off"` keeps other items inside it unmarked.
|
|
894
|
+
- `data-prepr-other-item="on"` marks them, also inside a header, footer or
|
|
895
|
+
navigation.
|
|
875
896
|
|
|
876
897
|
Typed text and changed fields show immediately. Structural changes, such as
|
|
877
898
|
adding or reordering components, appear after save.
|
package/dist/astro/index.cjs
CHANGED
|
@@ -31,7 +31,7 @@ __export(astro_exports, {
|
|
|
31
31
|
module.exports = __toCommonJS(astro_exports);
|
|
32
32
|
|
|
33
33
|
// src/version.ts
|
|
34
|
-
var VERSION = "0.5.0-rc.
|
|
34
|
+
var VERSION = "0.5.0-rc.12";
|
|
35
35
|
|
|
36
36
|
// src/core/features.ts
|
|
37
37
|
function isEnabled(config) {
|
|
@@ -490,8 +490,32 @@ function shapeLike(template, incoming) {
|
|
|
490
490
|
}
|
|
491
491
|
return out;
|
|
492
492
|
}
|
|
493
|
+
function isAsset(value) {
|
|
494
|
+
return isPlainObject(value) && (typeof value.url === "string" || value.__typename === "Asset");
|
|
495
|
+
}
|
|
496
|
+
function hasId(list, entry) {
|
|
497
|
+
return entry._id !== void 0 && list.some((c) => isPlainObject(c) && c._id === entry._id);
|
|
498
|
+
}
|
|
499
|
+
function isAssetValue(value) {
|
|
500
|
+
return Array.isArray(value) ? value.length > 0 && value.every(isAsset) : isAsset(value);
|
|
501
|
+
}
|
|
502
|
+
function keepRemovedAssets(current, next) {
|
|
503
|
+
const listed = /* @__PURE__ */ new Set();
|
|
504
|
+
for (const entry of next) {
|
|
505
|
+
if (isPlainObject(entry) && entry._id !== void 0) listed.add(entry._id);
|
|
506
|
+
}
|
|
507
|
+
let out = next;
|
|
508
|
+
current.forEach((entry, position) => {
|
|
509
|
+
if (!isPlainObject(entry) || entry._id === void 0) return;
|
|
510
|
+
if (listed.has(entry._id)) return;
|
|
511
|
+
if (out === next) out = [...next];
|
|
512
|
+
out.splice(Math.min(position, out.length), 0, entry);
|
|
513
|
+
});
|
|
514
|
+
return out;
|
|
515
|
+
}
|
|
493
516
|
function mergeStructured(current, incoming) {
|
|
494
517
|
if (incoming === null || Array.isArray(incoming) && !incoming.length) {
|
|
518
|
+
if (isAssetValue(current)) return current;
|
|
495
519
|
if (Array.isArray(current)) return current.length ? [] : current;
|
|
496
520
|
return null;
|
|
497
521
|
}
|
|
@@ -499,13 +523,18 @@ function mergeStructured(current, incoming) {
|
|
|
499
523
|
if (current === null || current === void 0) return incoming;
|
|
500
524
|
if (Array.isArray(current)) {
|
|
501
525
|
const template = current.find(isPlainObject);
|
|
502
|
-
|
|
526
|
+
const next = list.map((entry) => {
|
|
503
527
|
const match = current.find(
|
|
504
528
|
(c) => isPlainObject(c) && c._id !== void 0 && c._id === entry._id
|
|
505
529
|
);
|
|
506
530
|
if (isPlainObject(match)) return mergeObject(match, entry);
|
|
507
531
|
return isPlainObject(template) ? shapeLike(template, entry) : entry;
|
|
508
532
|
});
|
|
533
|
+
if (!isAssetValue(current) || list.some((entry) => !hasId(current, entry))) {
|
|
534
|
+
return next;
|
|
535
|
+
}
|
|
536
|
+
const kept = keepRemovedAssets(current, next);
|
|
537
|
+
return kept.length === current.length && kept.every((entry, i) => entry === current[i]) ? current : kept;
|
|
509
538
|
}
|
|
510
539
|
if (isPlainObject(current)) return mergeObject(current, list[0]);
|
|
511
540
|
return current;
|
package/dist/astro/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var VERSION = "0.5.0-rc.
|
|
2
|
+
var VERSION = "0.5.0-rc.12";
|
|
3
3
|
|
|
4
4
|
// src/core/features.ts
|
|
5
5
|
function isEnabled(config) {
|
|
@@ -462,8 +462,32 @@ function shapeLike(template, incoming) {
|
|
|
462
462
|
}
|
|
463
463
|
return out;
|
|
464
464
|
}
|
|
465
|
+
function isAsset(value) {
|
|
466
|
+
return isPlainObject(value) && (typeof value.url === "string" || value.__typename === "Asset");
|
|
467
|
+
}
|
|
468
|
+
function hasId(list, entry) {
|
|
469
|
+
return entry._id !== void 0 && list.some((c) => isPlainObject(c) && c._id === entry._id);
|
|
470
|
+
}
|
|
471
|
+
function isAssetValue(value) {
|
|
472
|
+
return Array.isArray(value) ? value.length > 0 && value.every(isAsset) : isAsset(value);
|
|
473
|
+
}
|
|
474
|
+
function keepRemovedAssets(current, next) {
|
|
475
|
+
const listed = /* @__PURE__ */ new Set();
|
|
476
|
+
for (const entry of next) {
|
|
477
|
+
if (isPlainObject(entry) && entry._id !== void 0) listed.add(entry._id);
|
|
478
|
+
}
|
|
479
|
+
let out = next;
|
|
480
|
+
current.forEach((entry, position) => {
|
|
481
|
+
if (!isPlainObject(entry) || entry._id === void 0) return;
|
|
482
|
+
if (listed.has(entry._id)) return;
|
|
483
|
+
if (out === next) out = [...next];
|
|
484
|
+
out.splice(Math.min(position, out.length), 0, entry);
|
|
485
|
+
});
|
|
486
|
+
return out;
|
|
487
|
+
}
|
|
465
488
|
function mergeStructured(current, incoming) {
|
|
466
489
|
if (incoming === null || Array.isArray(incoming) && !incoming.length) {
|
|
490
|
+
if (isAssetValue(current)) return current;
|
|
467
491
|
if (Array.isArray(current)) return current.length ? [] : current;
|
|
468
492
|
return null;
|
|
469
493
|
}
|
|
@@ -471,13 +495,18 @@ function mergeStructured(current, incoming) {
|
|
|
471
495
|
if (current === null || current === void 0) return incoming;
|
|
472
496
|
if (Array.isArray(current)) {
|
|
473
497
|
const template = current.find(isPlainObject);
|
|
474
|
-
|
|
498
|
+
const next = list.map((entry) => {
|
|
475
499
|
const match = current.find(
|
|
476
500
|
(c) => isPlainObject(c) && c._id !== void 0 && c._id === entry._id
|
|
477
501
|
);
|
|
478
502
|
if (isPlainObject(match)) return mergeObject(match, entry);
|
|
479
503
|
return isPlainObject(template) ? shapeLike(template, entry) : entry;
|
|
480
504
|
});
|
|
505
|
+
if (!isAssetValue(current) || list.some((entry) => !hasId(current, entry))) {
|
|
506
|
+
return next;
|
|
507
|
+
}
|
|
508
|
+
const kept = keepRemovedAssets(current, next);
|
|
509
|
+
return kept.length === current.length && kept.every((entry, i) => entry === current[i]) ? current : kept;
|
|
481
510
|
}
|
|
482
511
|
if (isPlainObject(current)) return mergeObject(current, list[0]);
|
|
483
512
|
return current;
|
|
@@ -101,8 +101,32 @@ function shapeLike(template, incoming) {
|
|
|
101
101
|
}
|
|
102
102
|
return out;
|
|
103
103
|
}
|
|
104
|
+
function isAsset(value) {
|
|
105
|
+
return isPlainObject(value) && (typeof value.url === "string" || value.__typename === "Asset");
|
|
106
|
+
}
|
|
107
|
+
function hasId(list, entry) {
|
|
108
|
+
return entry._id !== void 0 && list.some((c) => isPlainObject(c) && c._id === entry._id);
|
|
109
|
+
}
|
|
110
|
+
function isAssetValue(value) {
|
|
111
|
+
return Array.isArray(value) ? value.length > 0 && value.every(isAsset) : isAsset(value);
|
|
112
|
+
}
|
|
113
|
+
function keepRemovedAssets(current, next) {
|
|
114
|
+
const listed = /* @__PURE__ */ new Set();
|
|
115
|
+
for (const entry of next) {
|
|
116
|
+
if (isPlainObject(entry) && entry._id !== void 0) listed.add(entry._id);
|
|
117
|
+
}
|
|
118
|
+
let out = next;
|
|
119
|
+
current.forEach((entry, position) => {
|
|
120
|
+
if (!isPlainObject(entry) || entry._id === void 0) return;
|
|
121
|
+
if (listed.has(entry._id)) return;
|
|
122
|
+
if (out === next) out = [...next];
|
|
123
|
+
out.splice(Math.min(position, out.length), 0, entry);
|
|
124
|
+
});
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
104
127
|
function mergeStructured(current, incoming) {
|
|
105
128
|
if (incoming === null || Array.isArray(incoming) && !incoming.length) {
|
|
129
|
+
if (isAssetValue(current)) return current;
|
|
106
130
|
if (Array.isArray(current)) return current.length ? [] : current;
|
|
107
131
|
return null;
|
|
108
132
|
}
|
|
@@ -110,13 +134,18 @@ function mergeStructured(current, incoming) {
|
|
|
110
134
|
if (current === null || current === void 0) return incoming;
|
|
111
135
|
if (Array.isArray(current)) {
|
|
112
136
|
const template = current.find(isPlainObject);
|
|
113
|
-
|
|
137
|
+
const next = list.map((entry) => {
|
|
114
138
|
const match = current.find(
|
|
115
139
|
(c) => isPlainObject(c) && c._id !== void 0 && c._id === entry._id
|
|
116
140
|
);
|
|
117
141
|
if (isPlainObject(match)) return mergeObject(match, entry);
|
|
118
142
|
return isPlainObject(template) ? shapeLike(template, entry) : entry;
|
|
119
143
|
});
|
|
144
|
+
if (!isAssetValue(current) || list.some((entry) => !hasId(current, entry))) {
|
|
145
|
+
return next;
|
|
146
|
+
}
|
|
147
|
+
const kept = keepRemovedAssets(current, next);
|
|
148
|
+
return kept.length === current.length && kept.every((entry, i) => entry === current[i]) ? current : kept;
|
|
120
149
|
}
|
|
121
150
|
if (isPlainObject(current)) return mergeObject(current, list[0]);
|
|
122
151
|
return current;
|
|
@@ -239,6 +239,7 @@ function createIframeBridge(store, options = {}) {
|
|
|
239
239
|
const onReferences = options.onReferences;
|
|
240
240
|
const onAssets = options.onAssets;
|
|
241
241
|
const onAllowNavigation = options.onAllowNavigation;
|
|
242
|
+
const onItemChanged = options.onItemChanged;
|
|
242
243
|
let parentOrigin = null;
|
|
243
244
|
const onKeyDown = (event) => {
|
|
244
245
|
const key = event.key.toLowerCase();
|
|
@@ -329,6 +330,14 @@ function createIframeBridge(store, options = {}) {
|
|
|
329
330
|
debug.warn("allowNavigation handler failed", error);
|
|
330
331
|
}
|
|
331
332
|
}
|
|
333
|
+
if (data?.event === "prepr:itemChanged") {
|
|
334
|
+
if (typeof data.itemId !== "string" || !data.itemId) return;
|
|
335
|
+
try {
|
|
336
|
+
onItemChanged?.(data.itemId);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
debug.warn("itemChanged handler failed", error);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
332
341
|
};
|
|
333
342
|
return {
|
|
334
343
|
start() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isAllowedEditorOrigin
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-H3AFUPYD.js";
|
|
4
4
|
import {
|
|
5
5
|
indexSnapshot,
|
|
6
6
|
isLiveFieldChange,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
parseListEntries,
|
|
9
9
|
patchSnapshot,
|
|
10
10
|
syncListSnapshot
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CABGJW5X.js";
|
|
12
12
|
import {
|
|
13
13
|
createScopedLogger,
|
|
14
14
|
getTrustedParentOrigin,
|
|
@@ -2,12 +2,12 @@ import {
|
|
|
2
2
|
ALL_FEATURES_ENABLED,
|
|
3
3
|
VERSION,
|
|
4
4
|
resolveFeatures
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HVTNUCF7.js";
|
|
6
6
|
import {
|
|
7
7
|
createIframeBridge,
|
|
8
8
|
isLocale,
|
|
9
9
|
t
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-H3AFUPYD.js";
|
|
11
11
|
import {
|
|
12
12
|
createScopedLogger,
|
|
13
13
|
initDebugLogger,
|
|
@@ -2193,6 +2193,7 @@ var ABSOLUTE_HTTP = /^https?:\/\//i;
|
|
|
2193
2193
|
var SOURCE_URL_ATTRIBUTES = ["src", "data-src"];
|
|
2194
2194
|
var SOURCE_SET_ATTRIBUTES = ["srcset", "data-srcset"];
|
|
2195
2195
|
var ASSET_ATTR = "data-prepr-asset";
|
|
2196
|
+
var REMOVED_ATTR = "data-prepr-removed";
|
|
2196
2197
|
var ASSET_SOURCE_ATTRIBUTES = [
|
|
2197
2198
|
...SOURCE_URL_ATTRIBUTES,
|
|
2198
2199
|
...SOURCE_SET_ATTRIBUTES
|
|
@@ -2202,7 +2203,8 @@ var TAG_ATTRIBUTES = [
|
|
|
2202
2203
|
"data-prepr-id",
|
|
2203
2204
|
"data-prepr-field",
|
|
2204
2205
|
"data-prepr-entry-id",
|
|
2205
|
-
ASSET_ATTR
|
|
2206
|
+
ASSET_ATTR,
|
|
2207
|
+
REMOVED_ATTR
|
|
2206
2208
|
];
|
|
2207
2209
|
function decodeSegment(segment) {
|
|
2208
2210
|
try {
|
|
@@ -2321,11 +2323,22 @@ function besideOtherItem(img, isCurrentItem) {
|
|
|
2321
2323
|
return false;
|
|
2322
2324
|
}
|
|
2323
2325
|
function tagAssetImages(index, itemId, keys, options = {}) {
|
|
2324
|
-
const { isCurrentItem } = options;
|
|
2326
|
+
const { isCurrentItem, removed } = options;
|
|
2327
|
+
let showsRemoved = false;
|
|
2325
2328
|
for (const img of document.getElementsByTagName("img")) {
|
|
2326
2329
|
const ours = img.hasAttribute(ASSET_ATTR);
|
|
2327
|
-
|
|
2328
|
-
|
|
2330
|
+
let match = index.size ? matchAsset(img, index, keys) : void 0;
|
|
2331
|
+
let isRemoved = false;
|
|
2332
|
+
if (!match && removed?.size) {
|
|
2333
|
+
match = matchAsset(img, removed, keys);
|
|
2334
|
+
isRemoved = match !== void 0;
|
|
2335
|
+
}
|
|
2336
|
+
if (!ours && img.hasAttribute("data-prepr-encoded")) {
|
|
2337
|
+
const mark = isRemoved && (!isCurrentItem || isCurrentItem(img));
|
|
2338
|
+
setIfChanged(img, REMOVED_ATTR, mark ? "" : null);
|
|
2339
|
+
showsRemoved || (showsRemoved = mark);
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2329
2342
|
const asset = match && isCurrentItem && besideOtherItem(img, isCurrentItem) ? void 0 : match;
|
|
2330
2343
|
if (!asset) {
|
|
2331
2344
|
if (ours) untagAssetImage(img);
|
|
@@ -2336,10 +2349,14 @@ function tagAssetImages(index, itemId, keys, options = {}) {
|
|
|
2336
2349
|
setIfChanged(img, "data-prepr-id", itemId);
|
|
2337
2350
|
setIfChanged(img, "data-prepr-field", asset.field);
|
|
2338
2351
|
setIfChanged(img, "data-prepr-entry-id", asset.entryId ?? null);
|
|
2352
|
+
setIfChanged(img, REMOVED_ATTR, isRemoved ? "" : null);
|
|
2353
|
+
showsRemoved || (showsRemoved = isRemoved);
|
|
2339
2354
|
}
|
|
2355
|
+
return showsRemoved;
|
|
2340
2356
|
}
|
|
2341
2357
|
function untagAssetImages() {
|
|
2342
2358
|
document.querySelectorAll(`img[${ASSET_ATTR}]`).forEach(untagAssetImage);
|
|
2359
|
+
document.querySelectorAll(`img[${REMOVED_ATTR}]`).forEach((img) => img.removeAttribute(REMOVED_ATTR));
|
|
2343
2360
|
}
|
|
2344
2361
|
|
|
2345
2362
|
// src/core/visual-editor/navigation-guard.ts
|
|
@@ -2509,12 +2526,19 @@ var debug7 = createScopedLogger("visual-editor");
|
|
|
2509
2526
|
var ENCODED_SELECTOR2 = "[data-prepr-encoded]";
|
|
2510
2527
|
var REFERENCE_ATTR = "data-prepr-reference";
|
|
2511
2528
|
var REFERENCE_SELECTOR = `[${REFERENCE_ATTR}]`;
|
|
2529
|
+
var OTHER_ITEM_ATTR = "data-prepr-other-item";
|
|
2530
|
+
var OTHER_ITEM_SELECTOR = `[${OTHER_ITEM_ATTR}="on"],[${OTHER_ITEM_ATTR}="off"]`;
|
|
2531
|
+
var CHROME_SELECTOR = "header, footer, nav, [role=banner], [role=contentinfo], [role=navigation]";
|
|
2532
|
+
var SECTIONING_SELECTOR = "article, aside, main, nav, section";
|
|
2533
|
+
var PLAIN_HEADER_FOOTER = "header:not([role]), footer:not([role])";
|
|
2512
2534
|
var CURSOR_STYLE_MARKER = "data-prepr-visual-editor";
|
|
2513
|
-
var
|
|
2535
|
+
var REMOVED_STYLES = `img[${REMOVED_ATTR}]{opacity:.2!important;transition:opacity .2s ease}@media (prefers-reduced-motion:reduce){img[${REMOVED_ATTR}]{transition:none}}`;
|
|
2536
|
+
var CURSOR_STYLES = `${ENCODED_SELECTOR2}{cursor:pointer}html[data-prepr-ve-suspended] ${ENCODED_SELECTOR2}{cursor:auto}${REMOVED_STYLES}`;
|
|
2514
2537
|
var SUSPENDED_ATTR = "data-prepr-ve-suspended";
|
|
2515
2538
|
var FIND_RETRY_MS = 150;
|
|
2516
2539
|
var FIND_RETRIES = 6;
|
|
2517
2540
|
var MAX_CACHED_KEYS = 2e3;
|
|
2541
|
+
var SAVED_FADE_MS = 1e4;
|
|
2518
2542
|
var LAYOUT_MUTATIONS = {
|
|
2519
2543
|
childList: true,
|
|
2520
2544
|
subtree: true,
|
|
@@ -2557,6 +2581,9 @@ function createVisualEditor(opts) {
|
|
|
2557
2581
|
let guardEnabled = false;
|
|
2558
2582
|
let assetIndex = /* @__PURE__ */ new Map();
|
|
2559
2583
|
const assetKeys = /* @__PURE__ */ new Map();
|
|
2584
|
+
const removedAssets = /* @__PURE__ */ new Map();
|
|
2585
|
+
let saved = false;
|
|
2586
|
+
let savedTimeout = null;
|
|
2560
2587
|
const guard = createNavigationGuard({
|
|
2561
2588
|
onBlocked: (href) => opts.onNavigationBlocked?.(href),
|
|
2562
2589
|
showsEditedContent: () => showsEditedContent()
|
|
@@ -2588,10 +2615,26 @@ function createVisualEditor(opts) {
|
|
|
2588
2615
|
}
|
|
2589
2616
|
return null;
|
|
2590
2617
|
};
|
|
2618
|
+
const inSiteChrome = (el) => {
|
|
2619
|
+
let chrome = el.closest(CHROME_SELECTOR);
|
|
2620
|
+
while (chrome) {
|
|
2621
|
+
if (!chrome.matches(PLAIN_HEADER_FOOTER) || !chrome.parentElement?.closest(SECTIONING_SELECTOR)) {
|
|
2622
|
+
return true;
|
|
2623
|
+
}
|
|
2624
|
+
chrome = chrome.parentElement?.closest(CHROME_SELECTOR) ?? null;
|
|
2625
|
+
}
|
|
2626
|
+
return false;
|
|
2627
|
+
};
|
|
2628
|
+
const showsOtherItem = (el) => {
|
|
2629
|
+
const choice = el.closest(OTHER_ITEM_SELECTOR);
|
|
2630
|
+
if (choice) return choice.getAttribute(OTHER_ITEM_ATTR) === "on";
|
|
2631
|
+
return !inSiteChrome(el);
|
|
2632
|
+
};
|
|
2591
2633
|
const itemKind = (el) => {
|
|
2592
2634
|
if (isCurrentItem(el)) return "current";
|
|
2593
2635
|
if (!references) return "other";
|
|
2594
|
-
|
|
2636
|
+
if (linkedIdOf(el)) return "referenced";
|
|
2637
|
+
return showsOtherItem(el) ? "other" : null;
|
|
2595
2638
|
};
|
|
2596
2639
|
const referenceFieldOf = (el) => {
|
|
2597
2640
|
const linked = linkedIdOf(el);
|
|
@@ -2664,6 +2707,7 @@ function createVisualEditor(opts) {
|
|
|
2664
2707
|
}
|
|
2665
2708
|
return;
|
|
2666
2709
|
}
|
|
2710
|
+
if (kind === "other" && (e2.ctrlKey || e2.metaKey || e2.shiftKey)) return;
|
|
2667
2711
|
e2.preventDefault();
|
|
2668
2712
|
e2.stopPropagation();
|
|
2669
2713
|
const item = listItemIn(encoded, e2.target);
|
|
@@ -2671,11 +2715,13 @@ function createVisualEditor(opts) {
|
|
|
2671
2715
|
select(item?.element ?? encoded, encoded, item?.index);
|
|
2672
2716
|
const referenceField = kind === "referenced" ? referenceFieldOf(encoded) : void 0;
|
|
2673
2717
|
const linkedId = kind === "referenced" ? linkedIdOf(encoded) : null;
|
|
2718
|
+
const linkHref = kind === "other" ? leavingLinkHref(e2.target) : null;
|
|
2674
2719
|
opts.onEdit({
|
|
2675
2720
|
...readEditPayload(encoded),
|
|
2676
2721
|
...linkedId && { id: linkedId },
|
|
2677
2722
|
...item && { block: item.index },
|
|
2678
|
-
...referenceField && { referenceField }
|
|
2723
|
+
...referenceField && { referenceField },
|
|
2724
|
+
...linkHref && { linkHref }
|
|
2679
2725
|
});
|
|
2680
2726
|
};
|
|
2681
2727
|
const handleKey = (e2) => {
|
|
@@ -2736,15 +2782,32 @@ function createVisualEditor(opts) {
|
|
|
2736
2782
|
const el = block !== void 0 ? nthListItem(found, block) ?? found : found;
|
|
2737
2783
|
select(el, found, block);
|
|
2738
2784
|
}
|
|
2785
|
+
const hasAssets = () => assetIndex.size > 0 || removedAssets.size > 0;
|
|
2739
2786
|
function tagAssets() {
|
|
2740
2787
|
if (assetKeys.size > MAX_CACHED_KEYS) assetKeys.clear();
|
|
2741
|
-
tagAssetImages(assetIndex, currentItemId, assetKeys, {
|
|
2742
|
-
isCurrentItem: (el) => isCurrentItem(el)
|
|
2788
|
+
const showsRemoved = tagAssetImages(assetIndex, currentItemId, assetKeys, {
|
|
2789
|
+
isCurrentItem: (el) => isCurrentItem(el),
|
|
2790
|
+
removed: removedAssets
|
|
2743
2791
|
});
|
|
2792
|
+
if (saved && !showsRemoved) forgetRemoved();
|
|
2793
|
+
}
|
|
2794
|
+
function forgetRemoved() {
|
|
2795
|
+
saved = false;
|
|
2796
|
+
if (savedTimeout) clearTimeout(savedTimeout);
|
|
2797
|
+
savedTimeout = null;
|
|
2798
|
+
if (!removedAssets.size) return;
|
|
2799
|
+
removedAssets.clear();
|
|
2800
|
+
if (running) tagAssets();
|
|
2801
|
+
}
|
|
2802
|
+
function itemSaved() {
|
|
2803
|
+
if (!removedAssets.size) return;
|
|
2804
|
+
saved = true;
|
|
2805
|
+
if (savedTimeout) clearTimeout(savedTimeout);
|
|
2806
|
+
savedTimeout = setTimeout(forgetRemoved, SAVED_FADE_MS);
|
|
2744
2807
|
}
|
|
2745
2808
|
const handleLayoutFrame = () => {
|
|
2746
2809
|
mutationFrame = null;
|
|
2747
|
-
if (
|
|
2810
|
+
if (hasAssets()) tagAssets();
|
|
2748
2811
|
reselect();
|
|
2749
2812
|
const hovered = overlay.getHoverTarget();
|
|
2750
2813
|
if (hovered && !hovered.isConnected) {
|
|
@@ -2756,7 +2819,7 @@ function createVisualEditor(opts) {
|
|
|
2756
2819
|
};
|
|
2757
2820
|
const handleMutations = () => {
|
|
2758
2821
|
if (mutationFrame !== null) return;
|
|
2759
|
-
if (!selection && !overlay.getHoverTarget() && !
|
|
2822
|
+
if (!selection && !overlay.getHoverTarget() && !hasAssets()) return;
|
|
2760
2823
|
mutationFrame = requestAnimationFrame(handleLayoutFrame);
|
|
2761
2824
|
};
|
|
2762
2825
|
function injectCursorStyles() {
|
|
@@ -2797,7 +2860,7 @@ function createVisualEditor(opts) {
|
|
|
2797
2860
|
});
|
|
2798
2861
|
mutationObserver = new MutationObserver(handleMutations);
|
|
2799
2862
|
mutationObserver.observe(document.body, LAYOUT_MUTATIONS);
|
|
2800
|
-
if (
|
|
2863
|
+
if (hasAssets()) tagAssets();
|
|
2801
2864
|
syncGuard();
|
|
2802
2865
|
debug7.log("visual editor started");
|
|
2803
2866
|
}
|
|
@@ -2873,18 +2936,24 @@ function createVisualEditor(opts) {
|
|
|
2873
2936
|
});
|
|
2874
2937
|
}
|
|
2875
2938
|
function setCurrentItem(itemId, referenceList, componentIds) {
|
|
2939
|
+
if (itemId !== currentItemId) forgetRemoved();
|
|
2876
2940
|
currentItemId = itemId;
|
|
2877
2941
|
if (referenceList) setReferences(referenceList, componentIds);
|
|
2878
2942
|
else if (componentIds) ownComponents = new Set(componentIds);
|
|
2879
|
-
if (running &&
|
|
2943
|
+
if (running && hasAssets()) tagAssets();
|
|
2880
2944
|
const selected = overlay.getSelectedTarget();
|
|
2881
2945
|
const owner = selected ? encodedFrom(selected) : null;
|
|
2882
2946
|
if (owner && !isCurrentItem(owner)) clearSelection();
|
|
2883
2947
|
}
|
|
2884
2948
|
function setAssets(assets) {
|
|
2885
|
-
const hadAssets =
|
|
2886
|
-
|
|
2887
|
-
|
|
2949
|
+
const hadAssets = hasAssets();
|
|
2950
|
+
const next = createAssetIndex(assets);
|
|
2951
|
+
for (const [key, asset] of assetIndex) {
|
|
2952
|
+
if (!next.has(key)) removedAssets.set(key, asset);
|
|
2953
|
+
}
|
|
2954
|
+
for (const key of next.keys()) removedAssets.delete(key);
|
|
2955
|
+
assetIndex = next;
|
|
2956
|
+
if (running && (hadAssets || hasAssets())) tagAssets();
|
|
2888
2957
|
}
|
|
2889
2958
|
function setReferences(referenceList, componentIds) {
|
|
2890
2959
|
if (componentIds) ownComponents = new Set(componentIds);
|
|
@@ -2910,6 +2979,7 @@ function createVisualEditor(opts) {
|
|
|
2910
2979
|
setCurrentItem,
|
|
2911
2980
|
setReferences,
|
|
2912
2981
|
setAssets,
|
|
2982
|
+
itemSaved,
|
|
2913
2983
|
setLocale,
|
|
2914
2984
|
focusField,
|
|
2915
2985
|
setNavigationGuard,
|
|
@@ -2996,7 +3066,8 @@ function createPreprPreview(opts = {}) {
|
|
|
2996
3066
|
locale: contentLocale,
|
|
2997
3067
|
block,
|
|
2998
3068
|
entryId,
|
|
2999
|
-
referenceField
|
|
3069
|
+
referenceField,
|
|
3070
|
+
linkHref
|
|
3000
3071
|
}) => {
|
|
3001
3072
|
const safeHref = href ? safeEditUrl(href) : null;
|
|
3002
3073
|
if (href && !safeHref) {
|
|
@@ -3010,7 +3081,8 @@ function createPreprPreview(opts = {}) {
|
|
|
3010
3081
|
locale: contentLocale,
|
|
3011
3082
|
...block !== void 0 && { block },
|
|
3012
3083
|
...entryId && { entryId },
|
|
3013
|
-
...referenceField && { referenceField }
|
|
3084
|
+
...referenceField && { referenceField },
|
|
3085
|
+
...linkHref && { linkHref }
|
|
3014
3086
|
});
|
|
3015
3087
|
} else if (safeHref) {
|
|
3016
3088
|
window.open(safeHref, "_blank", "noopener,noreferrer");
|
|
@@ -3065,6 +3137,7 @@ function createPreprPreview(opts = {}) {
|
|
|
3065
3137
|
},
|
|
3066
3138
|
onAssets: (assets) => visualEditor?.setAssets(assets),
|
|
3067
3139
|
onAllowNavigation: (href) => visualEditor?.allowNavigation(href),
|
|
3140
|
+
onItemChanged: () => visualEditor?.itemSaved(),
|
|
3068
3141
|
onReferences: (referencedIds, componentIds) => visualEditor?.setReferences(referencedIds, componentIds),
|
|
3069
3142
|
// The editor selecting a field scrolls the matching element into view. The
|
|
3070
3143
|
// lookup relies on the attributes the stega scan writes, so it finds
|