@einblick/sdk 0.5.3 → 0.6.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/dist/client.d.ts +38 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +32 -1
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +77 -0
- package/dist/client.test.js.map +1 -1
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +176 -17
- package/dist/codegen.js.map +1 -1
- package/dist/codegen.test.js +156 -0
- package/dist/codegen.test.js.map +1 -1
- package/dist/react/i18n.d.ts +5 -0
- package/dist/react/i18n.d.ts.map +1 -1
- package/dist/react/i18n.js +10 -0
- package/dist/react/i18n.js.map +1 -1
- package/dist/react/provider.d.ts +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/provider.js +6 -1
- package/dist/react/provider.js.map +1 -1
- package/dist/react/runtime.d.ts +3 -1
- package/dist/react/runtime.d.ts.map +1 -1
- package/dist/react/runtime.js +898 -387
- package/dist/react/runtime.js.map +1 -1
- package/dist/react/shared.d.ts +2 -0
- package/dist/react/shared.d.ts.map +1 -1
- package/dist/react/shared.js +11 -5
- package/dist/react/shared.js.map +1 -1
- package/dist/react/types.d.ts +12 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/types.js +1 -0
- package/dist/react/types.js.map +1 -1
- package/package.json +3 -3
package/dist/react/runtime.js
CHANGED
|
@@ -1,98 +1,33 @@
|
|
|
1
|
-
import { EINBLICK_AUTH_SOURCE, EINBLICK_BRIDGE_SOURCE, EINBLICK_EDITOR_SOURCE, EINBLICK_PARENT_SOURCE, formatValueForText, isEditSessionExpired, readBindingFromElement, resolveAppOrigin, serializeBindingValue, shouldUseInlineEditor, } from './shared.js';
|
|
1
|
+
import { EINBLICK_AUTH_SOURCE, EINBLICK_BRIDGE_SOURCE, EINBLICK_EDITOR_SOURCE, EINBLICK_PARENT_SOURCE, formatValueForText, isMediaEditableBinding, isEditSessionExpired, readBindingFromElement, resolveAppOrigin, serializeBindingValue, shouldUseInlineEditor, } from './shared.js';
|
|
2
2
|
import { getEinblickSdkMessages, resolveEinblickSdkLocale, } from './i18n.js';
|
|
3
|
+
function normalizeResourceHints(hints) {
|
|
4
|
+
const normalized = [];
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
for (const hint of hints ?? []) {
|
|
7
|
+
const resourceSlug = hint.resourceSlug?.trim();
|
|
8
|
+
if (!resourceSlug)
|
|
9
|
+
continue;
|
|
10
|
+
const sourceType = hint.sourceType ?? 'cms';
|
|
11
|
+
const key = `${sourceType}:${resourceSlug}`;
|
|
12
|
+
if (seen.has(key))
|
|
13
|
+
continue;
|
|
14
|
+
seen.add(key);
|
|
15
|
+
normalized.push({
|
|
16
|
+
sourceType,
|
|
17
|
+
resourceSlug,
|
|
18
|
+
label: hint.label?.trim() || undefined,
|
|
19
|
+
mode: hint.mode,
|
|
20
|
+
recordIds: hint.recordIds?.filter((id) => id.trim().length > 0),
|
|
21
|
+
showInBottomBar: hint.showInBottomBar,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
3
26
|
const RUNTIME_STYLE_ID = 'einblick-edit-runtime-styles';
|
|
4
|
-
const RELATIVE_POSITION_SENTINEL = '__einblick_runtime_original_static__';
|
|
5
27
|
const EINBLICK_ACCENT_RGB = '250, 105, 62';
|
|
6
28
|
const EINBLICK_ACCENT_COLOR = `rgb(${EINBLICK_ACCENT_RGB})`;
|
|
7
29
|
const EINBLICK_ACCENT_BORDER = `rgba(${EINBLICK_ACCENT_RGB}, 0.92)`;
|
|
8
30
|
const CONTROL_BAR_HEIGHT = 44;
|
|
9
|
-
const INLINE_EDITOR_SHADOW_STYLES = `
|
|
10
|
-
:host {
|
|
11
|
-
display: block;
|
|
12
|
-
width: 100%;
|
|
13
|
-
color: rgb(15, 23, 42);
|
|
14
|
-
font-family: system-ui, sans-serif;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
*, *::before, *::after {
|
|
18
|
-
box-sizing: border-box;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
[data-einblick-inline-shell] {
|
|
22
|
-
display: flex;
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
gap: 0.75rem;
|
|
25
|
-
width: 100%;
|
|
26
|
-
color: rgb(15, 23, 42);
|
|
27
|
-
font-family: system-ui, sans-serif;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
[data-einblick-inline-control],
|
|
31
|
-
[data-einblick-inline-textarea],
|
|
32
|
-
[data-einblick-inline-select] {
|
|
33
|
-
appearance: none;
|
|
34
|
-
width: 100%;
|
|
35
|
-
min-width: 0;
|
|
36
|
-
margin: 0;
|
|
37
|
-
border-radius: 0.9rem;
|
|
38
|
-
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
39
|
-
background: rgb(255, 255, 255);
|
|
40
|
-
padding: 0.75rem 0.9rem;
|
|
41
|
-
font: 400 0.95rem/1.5 system-ui, sans-serif;
|
|
42
|
-
color: rgb(15, 23, 42);
|
|
43
|
-
box-shadow: none;
|
|
44
|
-
letter-spacing: normal;
|
|
45
|
-
text-transform: none;
|
|
46
|
-
text-indent: 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
[data-einblick-inline-control]:focus,
|
|
50
|
-
[data-einblick-inline-textarea]:focus,
|
|
51
|
-
[data-einblick-inline-select]:focus {
|
|
52
|
-
outline: 2px solid rgba(${EINBLICK_ACCENT_RGB}, 0.3);
|
|
53
|
-
outline-offset: 2px;
|
|
54
|
-
border-color: ${EINBLICK_ACCENT_COLOR};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
[data-einblick-inline-textarea] {
|
|
58
|
-
min-height: 8rem;
|
|
59
|
-
resize: vertical;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
[data-einblick-inline-actions] {
|
|
63
|
-
display: flex;
|
|
64
|
-
flex-wrap: wrap;
|
|
65
|
-
justify-content: flex-end;
|
|
66
|
-
gap: 0.5rem;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
[data-einblick-edit-action] {
|
|
70
|
-
appearance: none;
|
|
71
|
-
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
72
|
-
background: rgb(255, 255, 255);
|
|
73
|
-
color: rgb(15, 23, 42);
|
|
74
|
-
border-radius: 999px;
|
|
75
|
-
padding: 0.65rem 1rem;
|
|
76
|
-
font: 600 0.9rem/1 system-ui, sans-serif;
|
|
77
|
-
cursor: pointer;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
[data-einblick-edit-action]:disabled {
|
|
81
|
-
cursor: wait;
|
|
82
|
-
opacity: 0.72;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
[data-einblick-edit-action="primary"] {
|
|
86
|
-
border-color: ${EINBLICK_ACCENT_COLOR};
|
|
87
|
-
background: ${EINBLICK_ACCENT_COLOR};
|
|
88
|
-
color: rgb(255, 255, 255);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
[data-einblick-inline-error] {
|
|
92
|
-
font: 400 0.85rem/1.5 system-ui, sans-serif;
|
|
93
|
-
color: rgb(185, 28, 28);
|
|
94
|
-
}
|
|
95
|
-
`;
|
|
96
31
|
function getBrandBadgeSvg(size) {
|
|
97
32
|
return `
|
|
98
33
|
<svg viewBox="0 0 40 40" width="${size}" height="${size}" aria-hidden="true" focusable="false">
|
|
@@ -135,6 +70,32 @@ function createRandomId() {
|
|
|
135
70
|
}
|
|
136
71
|
return Math.random().toString(36).slice(2);
|
|
137
72
|
}
|
|
73
|
+
function stopEvent(event) {
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
}
|
|
77
|
+
function clamp(value, min, max) {
|
|
78
|
+
return Math.min(Math.max(value, min), max);
|
|
79
|
+
}
|
|
80
|
+
function isTextInputEvent(event) {
|
|
81
|
+
return (event.key.length === 1 ||
|
|
82
|
+
event.key === 'Enter' ||
|
|
83
|
+
event.key === 'Backspace' ||
|
|
84
|
+
event.key === 'Delete');
|
|
85
|
+
}
|
|
86
|
+
function fieldTypeAllowsMultiline(binding) {
|
|
87
|
+
return binding.fieldType === 'text' || binding.fieldType === 'markdown';
|
|
88
|
+
}
|
|
89
|
+
function getMediaAcceptValue(binding) {
|
|
90
|
+
return binding.fieldType === 'image' || binding.fieldType === 'images'
|
|
91
|
+
? 'image/*'
|
|
92
|
+
: '';
|
|
93
|
+
}
|
|
94
|
+
function getMediaActionLabel(binding, messages) {
|
|
95
|
+
return binding.fieldType === 'image' || binding.fieldType === 'images'
|
|
96
|
+
? messages.actions.replaceImage
|
|
97
|
+
: messages.actions.replaceFile;
|
|
98
|
+
}
|
|
138
99
|
function injectRuntimeStyles() {
|
|
139
100
|
if (typeof document === 'undefined') {
|
|
140
101
|
return;
|
|
@@ -149,15 +110,27 @@ function injectRuntimeStyles() {
|
|
|
149
110
|
scroll-margin-top: 96px;
|
|
150
111
|
}
|
|
151
112
|
|
|
152
|
-
[data-einblick-
|
|
153
|
-
|
|
154
|
-
|
|
113
|
+
[data-einblick-edit-outline],
|
|
114
|
+
[data-einblick-edit-field-outline] {
|
|
115
|
+
position: fixed;
|
|
116
|
+
z-index: 2147483643;
|
|
117
|
+
box-sizing: border-box;
|
|
118
|
+
pointer-events: none;
|
|
119
|
+
border-radius: var(--einblick-overlay-radius, 0.35rem);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
[data-einblick-edit-outline] {
|
|
123
|
+
border: 1px solid ${EINBLICK_ACCENT_BORDER};
|
|
124
|
+
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[data-einblick-edit-field-outline] {
|
|
128
|
+
border: 1px dashed rgba(${EINBLICK_ACCENT_RGB}, 0.78);
|
|
129
|
+
background: rgba(${EINBLICK_ACCENT_RGB}, 0.04);
|
|
155
130
|
}
|
|
156
131
|
|
|
157
132
|
[data-einblick-edit-controls] {
|
|
158
|
-
position:
|
|
159
|
-
top: 0.5rem;
|
|
160
|
-
right: 0.5rem;
|
|
133
|
+
position: fixed;
|
|
161
134
|
z-index: 2147483644;
|
|
162
135
|
display: inline-flex;
|
|
163
136
|
align-items: center;
|
|
@@ -165,7 +138,8 @@ function injectRuntimeStyles() {
|
|
|
165
138
|
}
|
|
166
139
|
|
|
167
140
|
[data-einblick-edit-button],
|
|
168
|
-
[data-einblick-create-button]
|
|
141
|
+
[data-einblick-create-button],
|
|
142
|
+
[data-einblick-field-button] {
|
|
169
143
|
border: 1px solid ${EINBLICK_ACCENT_COLOR};
|
|
170
144
|
border-radius: 999px;
|
|
171
145
|
padding: 0.3rem 0.7rem;
|
|
@@ -175,22 +149,46 @@ function injectRuntimeStyles() {
|
|
|
175
149
|
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.16);
|
|
176
150
|
}
|
|
177
151
|
|
|
178
|
-
[data-einblick-edit-button]
|
|
152
|
+
[data-einblick-edit-button],
|
|
153
|
+
[data-einblick-field-button="media"] {
|
|
179
154
|
background: ${EINBLICK_ACCENT_COLOR};
|
|
180
155
|
color: rgb(255, 255, 255);
|
|
181
156
|
}
|
|
182
157
|
|
|
183
|
-
[data-einblick-
|
|
158
|
+
[data-einblick-edit-button] {
|
|
159
|
+
padding: 0.42rem 0.85rem;
|
|
160
|
+
font-size: 13px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
[data-einblick-create-button],
|
|
164
|
+
[data-einblick-field-button="text"] {
|
|
184
165
|
background: rgb(255, 255, 255);
|
|
185
166
|
color: ${EINBLICK_ACCENT_COLOR};
|
|
186
167
|
}
|
|
187
168
|
|
|
188
169
|
[data-einblick-edit-button]:hover,
|
|
189
|
-
[data-einblick-create-button]:hover
|
|
170
|
+
[data-einblick-create-button]:hover,
|
|
171
|
+
[data-einblick-field-button]:hover {
|
|
190
172
|
background: rgb(255, 255, 255);
|
|
191
173
|
color: ${EINBLICK_ACCENT_COLOR};
|
|
192
174
|
}
|
|
193
175
|
|
|
176
|
+
[data-einblick-field-overlays] {
|
|
177
|
+
position: fixed;
|
|
178
|
+
inset: 0;
|
|
179
|
+
z-index: 2147483644;
|
|
180
|
+
pointer-events: none;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
[data-einblick-field-button] {
|
|
184
|
+
position: fixed;
|
|
185
|
+
z-index: 2147483644;
|
|
186
|
+
pointer-events: auto;
|
|
187
|
+
padding: 0.24rem 0.58rem;
|
|
188
|
+
font-size: 11px;
|
|
189
|
+
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.12);
|
|
190
|
+
}
|
|
191
|
+
|
|
194
192
|
[data-einblick-brand-badge] {
|
|
195
193
|
position: fixed;
|
|
196
194
|
right: 1rem;
|
|
@@ -340,64 +338,11 @@ function injectRuntimeStyles() {
|
|
|
340
338
|
}
|
|
341
339
|
|
|
342
340
|
[data-einblick-inline-editing="true"] {
|
|
343
|
-
|
|
344
|
-
outline-offset: 4px;
|
|
345
|
-
border-radius: 1rem;
|
|
346
|
-
background: rgba(${EINBLICK_ACCENT_RGB}, 0.08);
|
|
347
|
-
padding: 0.8rem;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
[data-einblick-inline-shell] {
|
|
351
|
-
display: flex;
|
|
352
|
-
flex-direction: column;
|
|
353
|
-
gap: 0.75rem;
|
|
354
|
-
width: 100%;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
[data-einblick-inline-control],
|
|
358
|
-
[data-einblick-inline-textarea],
|
|
359
|
-
[data-einblick-inline-select] {
|
|
360
|
-
width: 100%;
|
|
361
|
-
min-width: 0;
|
|
362
|
-
border-radius: 0.9rem;
|
|
363
|
-
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
364
|
-
background: rgb(255, 255, 255);
|
|
365
|
-
padding: 0.75rem 0.9rem;
|
|
366
|
-
font: 400 0.95rem/1.5 system-ui, sans-serif;
|
|
367
|
-
color: inherit;
|
|
368
|
-
box-sizing: border-box;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
[data-einblick-inline-textarea] {
|
|
372
|
-
min-height: 8rem;
|
|
373
|
-
resize: vertical;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
[data-einblick-inline-actions] {
|
|
377
|
-
display: flex;
|
|
378
|
-
flex-wrap: wrap;
|
|
379
|
-
justify-content: flex-end;
|
|
380
|
-
gap: 0.5rem;
|
|
341
|
+
cursor: text;
|
|
381
342
|
}
|
|
382
343
|
|
|
383
|
-
[data-einblick-
|
|
384
|
-
|
|
385
|
-
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
386
|
-
background: rgb(255, 255, 255);
|
|
387
|
-
padding: 0.65rem 1rem;
|
|
388
|
-
font: 600 0.9rem/1 system-ui, sans-serif;
|
|
389
|
-
cursor: pointer;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
[data-einblick-edit-action="primary"] {
|
|
393
|
-
border-color: ${EINBLICK_ACCENT_COLOR};
|
|
394
|
-
background: ${EINBLICK_ACCENT_COLOR};
|
|
395
|
-
color: rgb(255, 255, 255);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
[data-einblick-inline-error] {
|
|
399
|
-
font: 400 0.85rem/1.5 system-ui, sans-serif;
|
|
400
|
-
color: rgb(185, 28, 28);
|
|
344
|
+
[data-einblick-inline-editing="true"]:focus {
|
|
345
|
+
outline: none;
|
|
401
346
|
}
|
|
402
347
|
|
|
403
348
|
[data-einblick-editor-backdrop] {
|
|
@@ -472,6 +417,7 @@ class EinblickEditRuntime {
|
|
|
472
417
|
callbacks;
|
|
473
418
|
chrome;
|
|
474
419
|
reserveBottomSpace;
|
|
420
|
+
resourceHints;
|
|
475
421
|
locale;
|
|
476
422
|
messages;
|
|
477
423
|
bridgeNonce = createRandomId();
|
|
@@ -485,9 +431,12 @@ class EinblickEditRuntime {
|
|
|
485
431
|
bridgeFrame = null;
|
|
486
432
|
bridgePingInterval = null;
|
|
487
433
|
activeElement = null;
|
|
434
|
+
activeOutline = null;
|
|
488
435
|
hoverButtonContainer = null;
|
|
489
436
|
hoverButton = null;
|
|
490
437
|
hoverCreateButton = null;
|
|
438
|
+
quickFieldOverlayContainer = null;
|
|
439
|
+
quickFieldOverlays = [];
|
|
491
440
|
brandBadge = null;
|
|
492
441
|
brandPopover = null;
|
|
493
442
|
brandPopoverSiteName = null;
|
|
@@ -497,7 +446,7 @@ class EinblickEditRuntime {
|
|
|
497
446
|
brandPopoverLogoutButton = null;
|
|
498
447
|
bottomBarHost = null;
|
|
499
448
|
bottomBarSiteName = null;
|
|
500
|
-
|
|
449
|
+
bottomBarResourceList = null;
|
|
501
450
|
bottomBarMoreButton = null;
|
|
502
451
|
bottomBarMoreMenu = null;
|
|
503
452
|
bottomBarOpenAppButton = null;
|
|
@@ -510,6 +459,7 @@ class EinblickEditRuntime {
|
|
|
510
459
|
currentInlineTarget = null;
|
|
511
460
|
currentInlineBinding = null;
|
|
512
461
|
currentInlineRestoreState = null;
|
|
462
|
+
inlineSaveInFlight = null;
|
|
513
463
|
editorBackdrop = null;
|
|
514
464
|
editorNonce = null;
|
|
515
465
|
editorTarget = null;
|
|
@@ -518,14 +468,18 @@ class EinblickEditRuntime {
|
|
|
518
468
|
navigatorFrame = null;
|
|
519
469
|
navigatorNonce = null;
|
|
520
470
|
navigatorOpen = false;
|
|
471
|
+
navigatorFilter = null;
|
|
521
472
|
pendingInlineSaves = new Map();
|
|
473
|
+
pendingInlineMediaSaves = new Map();
|
|
522
474
|
pendingLogin = null;
|
|
475
|
+
pendingLogout = null;
|
|
523
476
|
constructor(options) {
|
|
524
477
|
this.siteKey = options.siteKey;
|
|
525
478
|
this.appOrigin = resolveAppOrigin(options.appOrigin, options.appUrl);
|
|
526
479
|
this.chrome = options.chrome ?? 'bar';
|
|
527
480
|
this.reserveBottomSpace =
|
|
528
481
|
options.reserveBottomSpace ?? this.chrome === 'bar';
|
|
482
|
+
this.resourceHints = normalizeResourceHints(options.resourceHints);
|
|
529
483
|
this.locale = resolveEinblickSdkLocale(options.locale);
|
|
530
484
|
this.messages = getEinblickSdkMessages(this.locale);
|
|
531
485
|
this.session =
|
|
@@ -548,6 +502,10 @@ class EinblickEditRuntime {
|
|
|
548
502
|
this.messages = getEinblickSdkMessages(nextLocale);
|
|
549
503
|
this.refreshLocalizedUi();
|
|
550
504
|
}
|
|
505
|
+
setResourceHints(hints) {
|
|
506
|
+
this.resourceHints = normalizeResourceHints(hints);
|
|
507
|
+
this.updateBottomBarResources();
|
|
508
|
+
}
|
|
551
509
|
start() {
|
|
552
510
|
if (this.started ||
|
|
553
511
|
typeof window === 'undefined' ||
|
|
@@ -580,6 +538,7 @@ class EinblickEditRuntime {
|
|
|
580
538
|
if (this.currentInlineTarget && !this.currentInlineTarget.isConnected) {
|
|
581
539
|
this.closeInlineEditor();
|
|
582
540
|
}
|
|
541
|
+
this.updateBottomBarResources();
|
|
583
542
|
});
|
|
584
543
|
this.mutationObserver.observe(document.body, {
|
|
585
544
|
childList: true,
|
|
@@ -603,15 +562,23 @@ class EinblickEditRuntime {
|
|
|
603
562
|
this.mutationObserver?.disconnect();
|
|
604
563
|
this.mutationObserver = null;
|
|
605
564
|
this.clearBridgePing();
|
|
565
|
+
if (this.pendingLogout) {
|
|
566
|
+
window.clearTimeout(this.pendingLogout.timeoutId);
|
|
567
|
+
this.pendingLogout.resolve(false);
|
|
568
|
+
this.pendingLogout = null;
|
|
569
|
+
}
|
|
606
570
|
this.bridgeFrame?.remove();
|
|
607
571
|
this.bridgeFrame = null;
|
|
608
572
|
this.setActiveElement(null);
|
|
573
|
+
this.activeOutline?.remove();
|
|
574
|
+
this.activeOutline = null;
|
|
609
575
|
this.hoverButtonContainer?.remove();
|
|
610
576
|
this.hoverButtonContainer = null;
|
|
611
577
|
this.hoverButton?.remove();
|
|
612
578
|
this.hoverButton = null;
|
|
613
579
|
this.hoverCreateButton?.remove();
|
|
614
580
|
this.hoverCreateButton = null;
|
|
581
|
+
this.clearQuickFieldOverlays();
|
|
615
582
|
this.brandBadge?.remove();
|
|
616
583
|
this.brandBadge = null;
|
|
617
584
|
this.brandPopover?.remove();
|
|
@@ -624,7 +591,7 @@ class EinblickEditRuntime {
|
|
|
624
591
|
this.bottomBarHost?.remove();
|
|
625
592
|
this.bottomBarHost = null;
|
|
626
593
|
this.bottomBarSiteName = null;
|
|
627
|
-
this.
|
|
594
|
+
this.bottomBarResourceList = null;
|
|
628
595
|
this.bottomBarMoreButton = null;
|
|
629
596
|
this.bottomBarMoreMenu = null;
|
|
630
597
|
this.bottomBarOpenAppButton = null;
|
|
@@ -645,6 +612,11 @@ class EinblickEditRuntime {
|
|
|
645
612
|
pending.reject(new Error(this.messages.errors.editingInterrupted));
|
|
646
613
|
}
|
|
647
614
|
this.pendingInlineSaves.clear();
|
|
615
|
+
for (const pending of this.pendingInlineMediaSaves.values()) {
|
|
616
|
+
window.clearTimeout(pending.timeoutId);
|
|
617
|
+
pending.reject(new Error(this.messages.errors.editingInterrupted));
|
|
618
|
+
}
|
|
619
|
+
this.pendingInlineMediaSaves.clear();
|
|
648
620
|
this.setState({
|
|
649
621
|
enabled: true,
|
|
650
622
|
active: false,
|
|
@@ -656,7 +628,7 @@ class EinblickEditRuntime {
|
|
|
656
628
|
}
|
|
657
629
|
refreshLocalizedUi() {
|
|
658
630
|
if (this.hoverButton) {
|
|
659
|
-
this.
|
|
631
|
+
this.updateHoverButtonLabel();
|
|
660
632
|
}
|
|
661
633
|
if (this.hoverCreateButton) {
|
|
662
634
|
this.hoverCreateButton.textContent = this.messages.actions.addRecord;
|
|
@@ -677,6 +649,7 @@ class EinblickEditRuntime {
|
|
|
677
649
|
}
|
|
678
650
|
this.updateBrandPopover();
|
|
679
651
|
this.updateBottomBar();
|
|
652
|
+
this.updateHoverChrome();
|
|
680
653
|
}
|
|
681
654
|
async login(options) {
|
|
682
655
|
if (typeof window === 'undefined') {
|
|
@@ -738,13 +711,24 @@ class EinblickEditRuntime {
|
|
|
738
711
|
this.setActiveElement(null);
|
|
739
712
|
return;
|
|
740
713
|
}
|
|
714
|
+
if (this.isSdkChromeTarget(event.target)) {
|
|
715
|
+
this.updateHoverChrome();
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
741
718
|
const target = this.findEditableTarget(event.target);
|
|
742
719
|
this.setActiveElement(target);
|
|
743
720
|
};
|
|
744
721
|
handleViewportChange = () => {
|
|
722
|
+
if (this.currentInlineTarget?.isConnected) {
|
|
723
|
+
this.ensureActiveOutline();
|
|
724
|
+
this.positionOutline(this.activeOutline, this.currentInlineTarget);
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
745
727
|
if (this.activeElement && !this.activeElement.isConnected) {
|
|
746
728
|
this.setActiveElement(null);
|
|
729
|
+
return;
|
|
747
730
|
}
|
|
731
|
+
this.updateHoverChrome();
|
|
748
732
|
};
|
|
749
733
|
handleWindowBlur = () => {
|
|
750
734
|
this.setBrandPopoverOpen(false);
|
|
@@ -785,8 +769,7 @@ class EinblickEditRuntime {
|
|
|
785
769
|
this.setActiveElement(null);
|
|
786
770
|
};
|
|
787
771
|
handleHoverButtonClick = (event) => {
|
|
788
|
-
event
|
|
789
|
-
event.stopPropagation();
|
|
772
|
+
stopEvent(event);
|
|
790
773
|
if (!this.activeElement) {
|
|
791
774
|
return;
|
|
792
775
|
}
|
|
@@ -794,11 +777,14 @@ class EinblickEditRuntime {
|
|
|
794
777
|
if (!binding) {
|
|
795
778
|
return;
|
|
796
779
|
}
|
|
780
|
+
if (binding.fieldKey && isMediaEditableBinding(binding)) {
|
|
781
|
+
this.openMediaPicker(this.activeElement, binding, this.hoverButton);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
797
784
|
this.openEditor(binding, this.activeElement);
|
|
798
785
|
};
|
|
799
786
|
handleCreateButtonClick = (event) => {
|
|
800
|
-
event
|
|
801
|
-
event.stopPropagation();
|
|
787
|
+
stopEvent(event);
|
|
802
788
|
if (!this.activeElement) {
|
|
803
789
|
return;
|
|
804
790
|
}
|
|
@@ -815,6 +801,16 @@ class EinblickEditRuntime {
|
|
|
815
801
|
this.setBottomBarMenuOpen(false);
|
|
816
802
|
return;
|
|
817
803
|
}
|
|
804
|
+
if (this.currentInlineTarget) {
|
|
805
|
+
if (this.currentInlineTarget.contains(target) ||
|
|
806
|
+
this.isSdkChromeTarget(target)) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
event.preventDefault();
|
|
810
|
+
event.stopImmediatePropagation();
|
|
811
|
+
void this.commitInlineEditor();
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
818
814
|
if (this.isBrandPopoverOpen() &&
|
|
819
815
|
!this.brandBadge?.contains(target) &&
|
|
820
816
|
!this.brandPopover?.contains(target)) {
|
|
@@ -889,6 +885,35 @@ class EinblickEditRuntime {
|
|
|
889
885
|
}
|
|
890
886
|
return;
|
|
891
887
|
}
|
|
888
|
+
if (message.type === 'logout-result') {
|
|
889
|
+
const pending = this.pendingLogout;
|
|
890
|
+
if (!pending || pending.requestId !== message.requestId) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
window.clearTimeout(pending.timeoutId);
|
|
894
|
+
this.pendingLogout = null;
|
|
895
|
+
if (!message.ok && message.message) {
|
|
896
|
+
this.callbacks.onError?.(message.message);
|
|
897
|
+
}
|
|
898
|
+
pending.resolve(message.ok);
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
if (message.type === 'inline-media-result') {
|
|
902
|
+
const pending = this.pendingInlineMediaSaves.get(message.requestId);
|
|
903
|
+
if (!pending) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
this.pendingInlineMediaSaves.delete(message.requestId);
|
|
907
|
+
window.clearTimeout(pending.timeoutId);
|
|
908
|
+
if (message.ok) {
|
|
909
|
+
pending.resolve({ fileId: message.fileId, value: message.value });
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const error = new Error(message.error || this.messages.errors.saveFieldFailed);
|
|
913
|
+
pending.reject(error);
|
|
914
|
+
this.callbacks.onError?.(error.message);
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
892
917
|
const pending = this.pendingInlineSaves.get(message.requestId);
|
|
893
918
|
if (!pending) {
|
|
894
919
|
return;
|
|
@@ -948,6 +973,7 @@ class EinblickEditRuntime {
|
|
|
948
973
|
collectionId: message.collectionId,
|
|
949
974
|
intent: message.intent,
|
|
950
975
|
recordId: message.recordId,
|
|
976
|
+
sourceType: message.sourceType,
|
|
951
977
|
resourceSlug: message.resourceSlug,
|
|
952
978
|
});
|
|
953
979
|
return;
|
|
@@ -956,6 +982,7 @@ class EinblickEditRuntime {
|
|
|
956
982
|
if (message.resourceSlug) {
|
|
957
983
|
void this.callbacks.onSave?.({
|
|
958
984
|
binding: {
|
|
985
|
+
sourceType: message.sourceType ?? 'cms',
|
|
959
986
|
resourceSlug: message.resourceSlug,
|
|
960
987
|
recordId: message.recordId ?? '',
|
|
961
988
|
resourceMode: 'collection',
|
|
@@ -963,6 +990,7 @@ class EinblickEditRuntime {
|
|
|
963
990
|
},
|
|
964
991
|
value: {
|
|
965
992
|
action: message.action,
|
|
993
|
+
sourceType: message.sourceType ?? 'cms',
|
|
966
994
|
recordId: message.recordId,
|
|
967
995
|
collectionId: message.collectionId,
|
|
968
996
|
},
|
|
@@ -994,6 +1022,7 @@ class EinblickEditRuntime {
|
|
|
994
1022
|
else if (this.editorBinding) {
|
|
995
1023
|
const nextBinding = {
|
|
996
1024
|
...this.editorBinding,
|
|
1025
|
+
sourceType: message.sourceType ?? this.editorBinding.sourceType ?? 'cms',
|
|
997
1026
|
recordId: message.recordId ?? this.editorBinding.recordId,
|
|
998
1027
|
};
|
|
999
1028
|
void this.callbacks.onSave?.({
|
|
@@ -1009,6 +1038,7 @@ class EinblickEditRuntime {
|
|
|
1009
1038
|
if (this.editorBinding) {
|
|
1010
1039
|
const nextBinding = {
|
|
1011
1040
|
...this.editorBinding,
|
|
1041
|
+
sourceType: message.sourceType ?? this.editorBinding.sourceType ?? 'cms',
|
|
1012
1042
|
resourceSlug: message.resourceSlug ?? this.editorBinding.resourceSlug,
|
|
1013
1043
|
recordId: message.recordId,
|
|
1014
1044
|
};
|
|
@@ -1060,16 +1090,23 @@ class EinblickEditRuntime {
|
|
|
1060
1090
|
container.hidden = true;
|
|
1061
1091
|
const editButton = document.createElement('button');
|
|
1062
1092
|
editButton.type = 'button';
|
|
1063
|
-
editButton.textContent = this.messages.actions.
|
|
1093
|
+
editButton.textContent = this.messages.actions.editElement;
|
|
1064
1094
|
editButton.setAttribute('data-einblick-edit-button', 'true');
|
|
1095
|
+
editButton.addEventListener('pointerdown', (event) => {
|
|
1096
|
+
event.stopPropagation();
|
|
1097
|
+
});
|
|
1065
1098
|
editButton.addEventListener('click', this.handleHoverButtonClick);
|
|
1066
1099
|
const createButton = document.createElement('button');
|
|
1067
1100
|
createButton.type = 'button';
|
|
1068
1101
|
createButton.textContent = this.messages.actions.addRecord;
|
|
1069
1102
|
createButton.hidden = true;
|
|
1070
1103
|
createButton.setAttribute('data-einblick-create-button', 'true');
|
|
1104
|
+
createButton.addEventListener('pointerdown', (event) => {
|
|
1105
|
+
event.stopPropagation();
|
|
1106
|
+
});
|
|
1071
1107
|
createButton.addEventListener('click', this.handleCreateButtonClick);
|
|
1072
1108
|
container.append(editButton, createButton);
|
|
1109
|
+
document.body.append(container);
|
|
1073
1110
|
this.hoverButtonContainer = container;
|
|
1074
1111
|
this.hoverButton = editButton;
|
|
1075
1112
|
this.hoverCreateButton = createButton;
|
|
@@ -1189,8 +1226,6 @@ class EinblickEditRuntime {
|
|
|
1189
1226
|
height: ${CONTROL_BAR_HEIGHT}px;
|
|
1190
1227
|
padding: 0 0.75rem;
|
|
1191
1228
|
background: ${EINBLICK_ACCENT_COLOR};
|
|
1192
|
-
border-top: 1px solid rgba(255, 255, 255, 0.24);
|
|
1193
|
-
box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.18);
|
|
1194
1229
|
}
|
|
1195
1230
|
|
|
1196
1231
|
.brand,
|
|
@@ -1220,6 +1255,25 @@ class EinblickEditRuntime {
|
|
|
1220
1255
|
font: 700 0.84rem/1.1 system-ui, sans-serif;
|
|
1221
1256
|
}
|
|
1222
1257
|
|
|
1258
|
+
.resources {
|
|
1259
|
+
display: inline-flex;
|
|
1260
|
+
align-items: center;
|
|
1261
|
+
gap: 0.35rem;
|
|
1262
|
+
min-width: 0;
|
|
1263
|
+
max-width: min(48rem, 54vw);
|
|
1264
|
+
overflow-x: auto;
|
|
1265
|
+
scrollbar-width: none;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
.resources::-webkit-scrollbar {
|
|
1269
|
+
display: none;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
.resource-button {
|
|
1273
|
+
flex: 0 0 auto;
|
|
1274
|
+
max-width: 12rem;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1223
1277
|
button {
|
|
1224
1278
|
appearance: none;
|
|
1225
1279
|
display: inline-flex;
|
|
@@ -1229,10 +1283,9 @@ class EinblickEditRuntime {
|
|
|
1229
1283
|
min-width: 0;
|
|
1230
1284
|
height: 2rem;
|
|
1231
1285
|
margin: 0;
|
|
1232
|
-
border: 1px solid rgba(255, 255, 255, 0.36);
|
|
1233
1286
|
border-radius: 0.35rem;
|
|
1234
|
-
background:
|
|
1235
|
-
color:
|
|
1287
|
+
background: #ffffff;
|
|
1288
|
+
color: #fa693e;
|
|
1236
1289
|
padding: 0 0.7rem;
|
|
1237
1290
|
font: 700 0.78rem/1 system-ui, sans-serif;
|
|
1238
1291
|
letter-spacing: 0;
|
|
@@ -1251,11 +1304,11 @@ class EinblickEditRuntime {
|
|
|
1251
1304
|
|
|
1252
1305
|
button:hover,
|
|
1253
1306
|
button[aria-expanded="true"] {
|
|
1254
|
-
|
|
1307
|
+
opacity: 0.8;
|
|
1255
1308
|
}
|
|
1256
1309
|
|
|
1257
1310
|
button:focus-visible {
|
|
1258
|
-
outline: 2px solid
|
|
1311
|
+
outline: 2px solid #ffffff;
|
|
1259
1312
|
outline-offset: 2px;
|
|
1260
1313
|
}
|
|
1261
1314
|
|
|
@@ -1341,14 +1394,8 @@ class EinblickEditRuntime {
|
|
|
1341
1394
|
brand.append(mark, siteName);
|
|
1342
1395
|
const actions = document.createElement('div');
|
|
1343
1396
|
actions.className = 'actions';
|
|
1344
|
-
const
|
|
1345
|
-
|
|
1346
|
-
cmsButton.addEventListener('click', (event) => {
|
|
1347
|
-
event.preventDefault();
|
|
1348
|
-
event.stopPropagation();
|
|
1349
|
-
this.setBottomBarMenuOpen(false);
|
|
1350
|
-
this.setNavigatorOpen(!this.isNavigatorOpen());
|
|
1351
|
-
});
|
|
1397
|
+
const resourceList = document.createElement('div');
|
|
1398
|
+
resourceList.className = 'resources';
|
|
1352
1399
|
const moreButton = document.createElement('button');
|
|
1353
1400
|
moreButton.type = 'button';
|
|
1354
1401
|
moreButton.className = 'secondary icon-button';
|
|
@@ -1386,13 +1433,13 @@ class EinblickEditRuntime {
|
|
|
1386
1433
|
void this.logoutFromEinblick();
|
|
1387
1434
|
});
|
|
1388
1435
|
moreMenu.append(openAppButton, logoutButton);
|
|
1389
|
-
actions.append(
|
|
1436
|
+
actions.append(resourceList, moreButton);
|
|
1390
1437
|
bar.append(brand, actions, moreMenu);
|
|
1391
1438
|
shadowRoot.append(style, bar);
|
|
1392
1439
|
document.body.append(host);
|
|
1393
1440
|
this.bottomBarHost = host;
|
|
1394
1441
|
this.bottomBarSiteName = siteName;
|
|
1395
|
-
this.
|
|
1442
|
+
this.bottomBarResourceList = resourceList;
|
|
1396
1443
|
this.bottomBarMoreButton = moreButton;
|
|
1397
1444
|
this.bottomBarMoreMenu = moreMenu;
|
|
1398
1445
|
this.bottomBarOpenAppButton = openAppButton;
|
|
@@ -1429,6 +1476,79 @@ class EinblickEditRuntime {
|
|
|
1429
1476
|
? this.messages.brand.authenticatedHint
|
|
1430
1477
|
: this.messages.brand.unauthenticatedHint;
|
|
1431
1478
|
}
|
|
1479
|
+
collectBottomBarResources() {
|
|
1480
|
+
const resources = new Map();
|
|
1481
|
+
for (const hint of this.resourceHints) {
|
|
1482
|
+
const key = `${hint.sourceType}:${hint.resourceSlug}`;
|
|
1483
|
+
if (hint.showInBottomBar === false) {
|
|
1484
|
+
resources.delete(key);
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
resources.set(key, hint);
|
|
1488
|
+
}
|
|
1489
|
+
if (typeof document !== 'undefined') {
|
|
1490
|
+
const elements = document.querySelectorAll('[data-einblick-editable="true"][data-einblick-resource]');
|
|
1491
|
+
elements.forEach((element) => {
|
|
1492
|
+
const binding = readBindingFromElement(element);
|
|
1493
|
+
if (!binding?.resourceSlug)
|
|
1494
|
+
return;
|
|
1495
|
+
const sourceType = binding.sourceType ?? 'cms';
|
|
1496
|
+
const key = `${sourceType}:${binding.resourceSlug}`;
|
|
1497
|
+
if (resources.has(key)) {
|
|
1498
|
+
const current = resources.get(key);
|
|
1499
|
+
if (binding.recordId &&
|
|
1500
|
+
!current.recordIds?.includes(binding.recordId)) {
|
|
1501
|
+
current.recordIds = [...(current.recordIds ?? []), binding.recordId];
|
|
1502
|
+
}
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
resources.set(key, {
|
|
1506
|
+
sourceType,
|
|
1507
|
+
resourceSlug: binding.resourceSlug,
|
|
1508
|
+
label: binding.label,
|
|
1509
|
+
mode: binding.resourceMode,
|
|
1510
|
+
recordIds: binding.recordId ? [binding.recordId] : undefined,
|
|
1511
|
+
});
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
return [...resources.values()];
|
|
1515
|
+
}
|
|
1516
|
+
updateBottomBarResources() {
|
|
1517
|
+
if (!this.bottomBarResourceList) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
this.bottomBarResourceList.replaceChildren();
|
|
1521
|
+
const resources = this.collectBottomBarResources();
|
|
1522
|
+
if (resources.length === 0) {
|
|
1523
|
+
const button = document.createElement('button');
|
|
1524
|
+
button.type = 'button';
|
|
1525
|
+
button.className = 'resource-button';
|
|
1526
|
+
button.textContent = this.messages.actions.cmsCollections;
|
|
1527
|
+
button.setAttribute('aria-expanded', this.isNavigatorOpen() ? 'true' : 'false');
|
|
1528
|
+
button.addEventListener('click', (event) => {
|
|
1529
|
+
event.preventDefault();
|
|
1530
|
+
event.stopPropagation();
|
|
1531
|
+
this.setBottomBarMenuOpen(false);
|
|
1532
|
+
this.setNavigatorOpen(!this.isNavigatorOpen());
|
|
1533
|
+
});
|
|
1534
|
+
this.bottomBarResourceList.append(button);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
for (const resource of resources) {
|
|
1538
|
+
const button = document.createElement('button');
|
|
1539
|
+
button.type = 'button';
|
|
1540
|
+
button.className = 'resource-button';
|
|
1541
|
+
button.textContent = resource.label ?? resource.resourceSlug;
|
|
1542
|
+
button.title = button.textContent;
|
|
1543
|
+
button.addEventListener('click', (event) => {
|
|
1544
|
+
event.preventDefault();
|
|
1545
|
+
event.stopPropagation();
|
|
1546
|
+
this.setBottomBarMenuOpen(false);
|
|
1547
|
+
this.openNavigator(resource);
|
|
1548
|
+
});
|
|
1549
|
+
this.bottomBarResourceList.append(button);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1432
1552
|
updateBottomBar() {
|
|
1433
1553
|
if (!this.bottomBarHost) {
|
|
1434
1554
|
this.applyBottomLayout(false);
|
|
@@ -1448,10 +1568,7 @@ class EinblickEditRuntime {
|
|
|
1448
1568
|
this.state.siteName?.trim() || this.messages.brand.connectedSite;
|
|
1449
1569
|
this.bottomBarSiteName.title = this.bottomBarSiteName.textContent;
|
|
1450
1570
|
}
|
|
1451
|
-
|
|
1452
|
-
this.bottomBarCmsButton.textContent = this.messages.actions.cmsCollections;
|
|
1453
|
-
this.bottomBarCmsButton.setAttribute('aria-expanded', this.isNavigatorOpen() ? 'true' : 'false');
|
|
1454
|
-
}
|
|
1571
|
+
this.updateBottomBarResources();
|
|
1455
1572
|
if (this.bottomBarMoreButton) {
|
|
1456
1573
|
this.bottomBarMoreButton.setAttribute('aria-label', this.messages.actions.moreActions);
|
|
1457
1574
|
this.bottomBarMoreButton.setAttribute('aria-expanded', this.isBottomBarMenuOpen() ? 'true' : 'false');
|
|
@@ -1463,7 +1580,7 @@ class EinblickEditRuntime {
|
|
|
1463
1580
|
if (this.bottomBarLogoutButton) {
|
|
1464
1581
|
this.bottomBarLogoutButton.textContent = this.messages.actions.logout;
|
|
1465
1582
|
}
|
|
1466
|
-
this.ensureNavigatorPanel();
|
|
1583
|
+
this.ensureNavigatorPanel(false, this.navigatorFilter);
|
|
1467
1584
|
if (this.navigatorFrame) {
|
|
1468
1585
|
this.navigatorFrame.title = this.messages.actions.cmsCollections;
|
|
1469
1586
|
}
|
|
@@ -1527,7 +1644,7 @@ class EinblickEditRuntime {
|
|
|
1527
1644
|
isNavigatorOpen() {
|
|
1528
1645
|
return this.navigatorOpen && !!this.navigatorPanel;
|
|
1529
1646
|
}
|
|
1530
|
-
ensureNavigatorPanel(reportErrors = false) {
|
|
1647
|
+
ensureNavigatorPanel(reportErrors = false, filter) {
|
|
1531
1648
|
if (this.navigatorPanel) {
|
|
1532
1649
|
return true;
|
|
1533
1650
|
}
|
|
@@ -1537,7 +1654,7 @@ class EinblickEditRuntime {
|
|
|
1537
1654
|
let navigatorUrl;
|
|
1538
1655
|
const nonce = createRandomId();
|
|
1539
1656
|
try {
|
|
1540
|
-
navigatorUrl = this.buildNavigatorUrl(nonce);
|
|
1657
|
+
navigatorUrl = this.buildNavigatorUrl(nonce, filter);
|
|
1541
1658
|
}
|
|
1542
1659
|
catch (error) {
|
|
1543
1660
|
if (reportErrors) {
|
|
@@ -1564,18 +1681,22 @@ class EinblickEditRuntime {
|
|
|
1564
1681
|
this.navigatorPanel = panel;
|
|
1565
1682
|
this.navigatorFrame = iframe;
|
|
1566
1683
|
this.navigatorNonce = nonce;
|
|
1684
|
+
this.navigatorFilter = filter ?? null;
|
|
1567
1685
|
return true;
|
|
1568
1686
|
}
|
|
1569
|
-
openNavigator() {
|
|
1687
|
+
openNavigator(filter) {
|
|
1570
1688
|
if (!this.state.isAuthenticated) {
|
|
1571
1689
|
this.callbacks.onError?.(this.messages.errors.signInToEditContent);
|
|
1572
1690
|
return;
|
|
1573
1691
|
}
|
|
1574
|
-
if (this.isNavigatorOpen()) {
|
|
1692
|
+
if (this.isNavigatorOpen() && !filter) {
|
|
1575
1693
|
return;
|
|
1576
1694
|
}
|
|
1695
|
+
if (this.isNavigatorOpen() && filter) {
|
|
1696
|
+
this.removeNavigatorPanel(false);
|
|
1697
|
+
}
|
|
1577
1698
|
this.setBottomBarMenuOpen(false);
|
|
1578
|
-
if (!this.ensureNavigatorPanel(true) || !this.navigatorPanel) {
|
|
1699
|
+
if (!this.ensureNavigatorPanel(true, filter) || !this.navigatorPanel) {
|
|
1579
1700
|
return;
|
|
1580
1701
|
}
|
|
1581
1702
|
this.navigatorOpen = true;
|
|
@@ -1602,6 +1723,7 @@ class EinblickEditRuntime {
|
|
|
1602
1723
|
this.navigatorPanel = null;
|
|
1603
1724
|
this.navigatorFrame = null;
|
|
1604
1725
|
this.navigatorNonce = null;
|
|
1726
|
+
this.navigatorFilter = null;
|
|
1605
1727
|
this.navigatorOpen = false;
|
|
1606
1728
|
if (hadNavigator && updateBottomBar) {
|
|
1607
1729
|
this.updateBottomBar();
|
|
@@ -1621,6 +1743,48 @@ class EinblickEditRuntime {
|
|
|
1621
1743
|
siteName: this.state.siteName,
|
|
1622
1744
|
errorMessage: undefined,
|
|
1623
1745
|
});
|
|
1746
|
+
const loggedOutViaBridge = await this.requestBridgeLogout();
|
|
1747
|
+
if (!loggedOutViaBridge) {
|
|
1748
|
+
await this.logoutViaPopup(sessionToken);
|
|
1749
|
+
}
|
|
1750
|
+
this.reloadBridge();
|
|
1751
|
+
}
|
|
1752
|
+
requestBridgeLogout() {
|
|
1753
|
+
if (typeof window === 'undefined' || this.pendingLogout) {
|
|
1754
|
+
return Promise.resolve(false);
|
|
1755
|
+
}
|
|
1756
|
+
const target = this.bridgeFrame?.contentWindow;
|
|
1757
|
+
if (!target) {
|
|
1758
|
+
return Promise.resolve(false);
|
|
1759
|
+
}
|
|
1760
|
+
const requestId = createRandomId();
|
|
1761
|
+
return new Promise((resolve) => {
|
|
1762
|
+
const timeoutId = window.setTimeout(() => {
|
|
1763
|
+
if (this.pendingLogout?.requestId !== requestId) {
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
this.pendingLogout = null;
|
|
1767
|
+
resolve(false);
|
|
1768
|
+
}, 2500);
|
|
1769
|
+
this.pendingLogout = { requestId, resolve, timeoutId };
|
|
1770
|
+
try {
|
|
1771
|
+
target.postMessage({
|
|
1772
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
1773
|
+
type: 'logout',
|
|
1774
|
+
nonce: this.bridgeNonce,
|
|
1775
|
+
requestId,
|
|
1776
|
+
}, this.appOrigin);
|
|
1777
|
+
}
|
|
1778
|
+
catch {
|
|
1779
|
+
window.clearTimeout(timeoutId);
|
|
1780
|
+
if (this.pendingLogout?.requestId === requestId) {
|
|
1781
|
+
this.pendingLogout = null;
|
|
1782
|
+
}
|
|
1783
|
+
resolve(false);
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
async logoutViaPopup(sessionToken) {
|
|
1624
1788
|
const logoutUrl = this.buildBridgeUrl({
|
|
1625
1789
|
mode: 'logout',
|
|
1626
1790
|
nonce: createRandomId(),
|
|
@@ -1647,28 +1811,11 @@ class EinblickEditRuntime {
|
|
|
1647
1811
|
}
|
|
1648
1812
|
}, 400);
|
|
1649
1813
|
});
|
|
1650
|
-
this.reloadBridge();
|
|
1651
1814
|
}
|
|
1652
1815
|
setActiveElement(element) {
|
|
1653
1816
|
if (this.activeElement === element) {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
!element.contains(this.hoverButtonContainer)) {
|
|
1657
|
-
element.append(this.hoverButtonContainer);
|
|
1658
|
-
}
|
|
1659
|
-
this.updateHoverButtonVisibility(element);
|
|
1660
|
-
return;
|
|
1661
|
-
}
|
|
1662
|
-
if (this.activeElement) {
|
|
1663
|
-
this.activeElement.removeAttribute('data-einblick-editable-active');
|
|
1664
|
-
const originalPosition = this.activeElement.dataset.einblickRuntimeOriginalPosition;
|
|
1665
|
-
if (originalPosition !== undefined) {
|
|
1666
|
-
this.activeElement.style.position =
|
|
1667
|
-
originalPosition === RELATIVE_POSITION_SENTINEL
|
|
1668
|
-
? ''
|
|
1669
|
-
: originalPosition;
|
|
1670
|
-
delete this.activeElement.dataset.einblickRuntimeOriginalPosition;
|
|
1671
|
-
}
|
|
1817
|
+
this.updateHoverChrome();
|
|
1818
|
+
return;
|
|
1672
1819
|
}
|
|
1673
1820
|
this.activeElement = element;
|
|
1674
1821
|
if (!element ||
|
|
@@ -1677,22 +1824,176 @@ class EinblickEditRuntime {
|
|
|
1677
1824
|
!this.state.isAuthenticated) {
|
|
1678
1825
|
if (this.hoverButtonContainer) {
|
|
1679
1826
|
this.hoverButtonContainer.hidden = true;
|
|
1680
|
-
this.hoverButtonContainer.remove();
|
|
1681
1827
|
}
|
|
1828
|
+
this.activeOutline?.remove();
|
|
1829
|
+
this.activeOutline = null;
|
|
1830
|
+
this.clearQuickFieldOverlays();
|
|
1682
1831
|
if (this.hoverCreateButton) {
|
|
1683
1832
|
this.hoverCreateButton.hidden = true;
|
|
1684
1833
|
}
|
|
1685
1834
|
return;
|
|
1686
1835
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
element.style.position || RELATIVE_POSITION_SENTINEL;
|
|
1691
|
-
element.style.position = 'relative';
|
|
1692
|
-
}
|
|
1836
|
+
this.ensureActiveOutline();
|
|
1837
|
+
this.hoverButtonContainer.hidden = false;
|
|
1838
|
+
this.updateHoverButtonLabel();
|
|
1693
1839
|
this.updateHoverButtonVisibility(element);
|
|
1840
|
+
this.renderQuickFieldOverlays(element);
|
|
1841
|
+
this.updateHoverChrome();
|
|
1842
|
+
}
|
|
1843
|
+
ensureActiveOutline() {
|
|
1844
|
+
if (this.activeOutline || typeof document === 'undefined') {
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
const outline = document.createElement('div');
|
|
1848
|
+
outline.setAttribute('data-einblick-edit-outline', 'true');
|
|
1849
|
+
document.body.append(outline);
|
|
1850
|
+
this.activeOutline = outline;
|
|
1851
|
+
}
|
|
1852
|
+
updateHoverChrome() {
|
|
1853
|
+
if (!this.activeElement || !this.state.isAuthenticated) {
|
|
1854
|
+
this.activeOutline?.remove();
|
|
1855
|
+
this.activeOutline = null;
|
|
1856
|
+
if (this.hoverButtonContainer) {
|
|
1857
|
+
this.hoverButtonContainer.hidden = true;
|
|
1858
|
+
}
|
|
1859
|
+
this.clearQuickFieldOverlays();
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (!this.activeElement.isConnected) {
|
|
1863
|
+
this.setActiveElement(null);
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
this.ensureActiveOutline();
|
|
1867
|
+
const rect = this.activeElement.getBoundingClientRect();
|
|
1868
|
+
const isVisible = this.positionOutline(this.activeOutline, this.activeElement);
|
|
1869
|
+
if (!isVisible || rect.width <= 0 || rect.height <= 0) {
|
|
1870
|
+
if (this.hoverButtonContainer) {
|
|
1871
|
+
this.hoverButtonContainer.hidden = true;
|
|
1872
|
+
}
|
|
1873
|
+
this.clearQuickFieldOverlays();
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
this.updateHoverButtonLabel();
|
|
1877
|
+
this.updateHoverButtonVisibility(this.activeElement);
|
|
1878
|
+
this.positionHoverControls(rect);
|
|
1879
|
+
this.updateQuickFieldOverlayPositions();
|
|
1880
|
+
}
|
|
1881
|
+
positionOutline(outline, target) {
|
|
1882
|
+
if (!outline) {
|
|
1883
|
+
return false;
|
|
1884
|
+
}
|
|
1885
|
+
const rect = target.getBoundingClientRect();
|
|
1886
|
+
if (rect.width <= 0 || rect.height <= 0) {
|
|
1887
|
+
outline.hidden = true;
|
|
1888
|
+
return false;
|
|
1889
|
+
}
|
|
1890
|
+
const style = window.getComputedStyle(target);
|
|
1891
|
+
outline.hidden = false;
|
|
1892
|
+
outline.style.setProperty('--einblick-overlay-radius', style.borderRadius || '0.35rem');
|
|
1893
|
+
outline.style.left = `${Math.round(rect.left)}px`;
|
|
1894
|
+
outline.style.top = `${Math.round(rect.top)}px`;
|
|
1895
|
+
outline.style.width = `${Math.round(rect.width)}px`;
|
|
1896
|
+
outline.style.height = `${Math.round(rect.height)}px`;
|
|
1897
|
+
return true;
|
|
1898
|
+
}
|
|
1899
|
+
positionHoverControls(rect) {
|
|
1900
|
+
if (!this.hoverButtonContainer) {
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1694
1903
|
this.hoverButtonContainer.hidden = false;
|
|
1695
|
-
|
|
1904
|
+
const margin = 8;
|
|
1905
|
+
const width = this.hoverButtonContainer.offsetWidth || 180;
|
|
1906
|
+
const height = this.hoverButtonContainer.offsetHeight || 32;
|
|
1907
|
+
const left = clamp(rect.right - width - margin, margin, Math.max(margin, window.innerWidth - width - margin));
|
|
1908
|
+
const top = clamp(rect.top + margin, margin, Math.max(margin, window.innerHeight - height - margin));
|
|
1909
|
+
this.hoverButtonContainer.style.left = `${Math.round(left)}px`;
|
|
1910
|
+
this.hoverButtonContainer.style.top = `${Math.round(top)}px`;
|
|
1911
|
+
}
|
|
1912
|
+
clearQuickFieldOverlays() {
|
|
1913
|
+
this.quickFieldOverlayContainer?.remove();
|
|
1914
|
+
this.quickFieldOverlayContainer = null;
|
|
1915
|
+
this.quickFieldOverlays = [];
|
|
1916
|
+
}
|
|
1917
|
+
renderQuickFieldOverlays(element) {
|
|
1918
|
+
this.clearQuickFieldOverlays();
|
|
1919
|
+
const targets = this.getQuickEditableTargets(element);
|
|
1920
|
+
if (targets.length === 0 || typeof document === 'undefined') {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const container = document.createElement('div');
|
|
1924
|
+
container.setAttribute('data-einblick-field-overlays', 'true');
|
|
1925
|
+
this.quickFieldOverlays = targets.map((target) => {
|
|
1926
|
+
const binding = readBindingFromElement(target);
|
|
1927
|
+
const outline = document.createElement('div');
|
|
1928
|
+
outline.setAttribute('data-einblick-edit-field-outline', 'true');
|
|
1929
|
+
const button = document.createElement('button');
|
|
1930
|
+
button.type = 'button';
|
|
1931
|
+
button.setAttribute('data-einblick-field-button', binding && isMediaEditableBinding(binding) ? 'media' : 'text');
|
|
1932
|
+
button.textContent =
|
|
1933
|
+
binding && isMediaEditableBinding(binding)
|
|
1934
|
+
? getMediaActionLabel(binding, this.messages)
|
|
1935
|
+
: this.messages.actions.editText;
|
|
1936
|
+
button.addEventListener('pointerdown', (event) => {
|
|
1937
|
+
event.stopPropagation();
|
|
1938
|
+
});
|
|
1939
|
+
button.addEventListener('click', (event) => {
|
|
1940
|
+
stopEvent(event);
|
|
1941
|
+
const nextBinding = readBindingFromElement(target);
|
|
1942
|
+
if (!nextBinding) {
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
if (isMediaEditableBinding(nextBinding)) {
|
|
1946
|
+
this.openMediaPicker(target, nextBinding, button);
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
this.openInlineEditor(target, nextBinding);
|
|
1950
|
+
});
|
|
1951
|
+
container.append(outline, button);
|
|
1952
|
+
return { target, outline, button };
|
|
1953
|
+
});
|
|
1954
|
+
document.body.append(container);
|
|
1955
|
+
this.quickFieldOverlayContainer = container;
|
|
1956
|
+
this.updateQuickFieldOverlayPositions();
|
|
1957
|
+
}
|
|
1958
|
+
updateQuickFieldOverlayPositions() {
|
|
1959
|
+
if (!this.quickFieldOverlayContainer) {
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
for (const overlay of this.quickFieldOverlays) {
|
|
1963
|
+
if (!overlay.target.isConnected) {
|
|
1964
|
+
overlay.outline.hidden = true;
|
|
1965
|
+
overlay.button.hidden = true;
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
const rect = overlay.target.getBoundingClientRect();
|
|
1969
|
+
const isVisible = this.positionOutline(overlay.outline, overlay.target);
|
|
1970
|
+
overlay.button.hidden = !isVisible;
|
|
1971
|
+
if (!isVisible) {
|
|
1972
|
+
continue;
|
|
1973
|
+
}
|
|
1974
|
+
const margin = 4;
|
|
1975
|
+
const width = overlay.button.offsetWidth || 96;
|
|
1976
|
+
const height = overlay.button.offsetHeight || 26;
|
|
1977
|
+
const left = clamp(rect.left + margin, margin, Math.max(margin, window.innerWidth - width - margin));
|
|
1978
|
+
const top = clamp(rect.top + margin, margin, Math.max(margin, window.innerHeight - height - margin));
|
|
1979
|
+
overlay.button.style.left = `${Math.round(left)}px`;
|
|
1980
|
+
overlay.button.style.top = `${Math.round(top)}px`;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
updateHoverButtonLabel() {
|
|
1984
|
+
if (!this.hoverButton || !this.activeElement) {
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
const binding = readBindingFromElement(this.activeElement);
|
|
1988
|
+
if (!binding?.fieldKey) {
|
|
1989
|
+
this.hoverButton.textContent = this.messages.actions.editElement;
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
this.hoverButton.textContent = isMediaEditableBinding(binding)
|
|
1993
|
+
? getMediaActionLabel(binding, this.messages)
|
|
1994
|
+
: shouldUseInlineEditor(binding)
|
|
1995
|
+
? this.messages.actions.editText
|
|
1996
|
+
: this.messages.actions.edit;
|
|
1696
1997
|
}
|
|
1697
1998
|
reloadBridge() {
|
|
1698
1999
|
this.clearBridgePing();
|
|
@@ -1765,6 +2066,7 @@ class EinblickEditRuntime {
|
|
|
1765
2066
|
url.searchParams.set('nonce', nonce);
|
|
1766
2067
|
url.searchParams.set('sessionToken', sessionToken);
|
|
1767
2068
|
url.searchParams.set('returnTo', window.location.href);
|
|
2069
|
+
url.searchParams.set('sourceType', binding.sourceType ?? 'cms');
|
|
1768
2070
|
url.searchParams.set('resourceSlug', binding.resourceSlug);
|
|
1769
2071
|
url.searchParams.set('recordId', binding.recordId);
|
|
1770
2072
|
if (intent === 'create') {
|
|
@@ -1775,7 +2077,7 @@ class EinblickEditRuntime {
|
|
|
1775
2077
|
}
|
|
1776
2078
|
return url.toString();
|
|
1777
2079
|
}
|
|
1778
|
-
buildNavigatorUrl(nonce) {
|
|
2080
|
+
buildNavigatorUrl(nonce, filter) {
|
|
1779
2081
|
const sessionToken = this.getActiveSessionToken();
|
|
1780
2082
|
if (!sessionToken) {
|
|
1781
2083
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
@@ -1784,6 +2086,15 @@ class EinblickEditRuntime {
|
|
|
1784
2086
|
url.searchParams.set('origin', window.location.origin);
|
|
1785
2087
|
url.searchParams.set('nonce', nonce);
|
|
1786
2088
|
url.searchParams.set('sessionToken', sessionToken);
|
|
2089
|
+
if (filter?.sourceType) {
|
|
2090
|
+
url.searchParams.set('sourceType', filter.sourceType);
|
|
2091
|
+
}
|
|
2092
|
+
if (filter?.resourceSlug) {
|
|
2093
|
+
url.searchParams.set('resourceSlug', filter.resourceSlug);
|
|
2094
|
+
}
|
|
2095
|
+
if (filter?.recordIds && filter.recordIds.length > 0) {
|
|
2096
|
+
url.searchParams.set('recordIds', filter.recordIds.join(','));
|
|
2097
|
+
}
|
|
1787
2098
|
return url.toString();
|
|
1788
2099
|
}
|
|
1789
2100
|
buildCollectionEditorUrl(args) {
|
|
@@ -1796,7 +2107,11 @@ class EinblickEditRuntime {
|
|
|
1796
2107
|
url.searchParams.set('nonce', args.nonce);
|
|
1797
2108
|
url.searchParams.set('sessionToken', sessionToken);
|
|
1798
2109
|
url.searchParams.set('returnTo', window.location.href);
|
|
2110
|
+
url.searchParams.set('sourceType', args.sourceType ?? 'cms');
|
|
1799
2111
|
url.searchParams.set('collectionId', args.collectionId);
|
|
2112
|
+
if (args.resourceSlug) {
|
|
2113
|
+
url.searchParams.set('resourceSlug', args.resourceSlug);
|
|
2114
|
+
}
|
|
1800
2115
|
url.searchParams.set('intent', args.intent);
|
|
1801
2116
|
if (args.recordId) {
|
|
1802
2117
|
url.searchParams.set('recordId', args.recordId);
|
|
@@ -1828,6 +2143,7 @@ class EinblickEditRuntime {
|
|
|
1828
2143
|
}
|
|
1829
2144
|
const selector = [
|
|
1830
2145
|
'[data-einblick-editable="true"]',
|
|
2146
|
+
`[data-einblick-source-type="${CSS.escape(binding.sourceType ?? 'cms')}"]`,
|
|
1831
2147
|
`[data-einblick-resource="${CSS.escape(binding.resourceSlug)}"]`,
|
|
1832
2148
|
].join('');
|
|
1833
2149
|
const elements = document.querySelectorAll(selector);
|
|
@@ -1845,11 +2161,74 @@ class EinblickEditRuntime {
|
|
|
1845
2161
|
return null;
|
|
1846
2162
|
}
|
|
1847
2163
|
const editableTarget = target.closest('[data-einblick-editable="true"]');
|
|
1848
|
-
|
|
2164
|
+
if (!editableTarget) {
|
|
2165
|
+
return null;
|
|
2166
|
+
}
|
|
2167
|
+
const binding = readBindingFromElement(editableTarget);
|
|
2168
|
+
if (!binding?.fieldKey) {
|
|
2169
|
+
return editableTarget;
|
|
2170
|
+
}
|
|
2171
|
+
const entryTarget = this.findEntryTargetForField(editableTarget, binding);
|
|
2172
|
+
return entryTarget ?? editableTarget;
|
|
2173
|
+
}
|
|
2174
|
+
findEntryTargetForField(fieldElement, binding) {
|
|
2175
|
+
let parent = fieldElement.parentElement;
|
|
2176
|
+
while (parent) {
|
|
2177
|
+
const parentBinding = readBindingFromElement(parent);
|
|
2178
|
+
if (parentBinding &&
|
|
2179
|
+
!parentBinding.fieldKey &&
|
|
2180
|
+
(parentBinding.sourceType ?? 'cms') === (binding.sourceType ?? 'cms') &&
|
|
2181
|
+
parentBinding.resourceSlug === binding.resourceSlug &&
|
|
2182
|
+
parentBinding.recordId === binding.recordId) {
|
|
2183
|
+
return parent;
|
|
2184
|
+
}
|
|
2185
|
+
parent = parent.parentElement;
|
|
2186
|
+
}
|
|
2187
|
+
return null;
|
|
2188
|
+
}
|
|
2189
|
+
getQuickEditableTargets(element) {
|
|
2190
|
+
const binding = readBindingFromElement(element);
|
|
2191
|
+
if (!binding) {
|
|
2192
|
+
return [];
|
|
2193
|
+
}
|
|
2194
|
+
if (binding.fieldKey) {
|
|
2195
|
+
return shouldUseInlineEditor(binding) || isMediaEditableBinding(binding)
|
|
2196
|
+
? [element]
|
|
2197
|
+
: [];
|
|
2198
|
+
}
|
|
2199
|
+
const selector = [
|
|
2200
|
+
'[data-einblick-editable="true"]',
|
|
2201
|
+
`[data-einblick-source-type="${CSS.escape(binding.sourceType ?? 'cms')}"]`,
|
|
2202
|
+
`[data-einblick-resource="${CSS.escape(binding.resourceSlug)}"]`,
|
|
2203
|
+
`[data-einblick-record-id="${CSS.escape(binding.recordId)}"]`,
|
|
2204
|
+
'[data-einblick-field-key]',
|
|
2205
|
+
].join('');
|
|
2206
|
+
const fields = Array.from(element.querySelectorAll(selector));
|
|
2207
|
+
return fields
|
|
2208
|
+
.filter((candidate) => {
|
|
2209
|
+
const candidateBinding = readBindingFromElement(candidate);
|
|
2210
|
+
return (!!candidateBinding &&
|
|
2211
|
+
(shouldUseInlineEditor(candidateBinding) ||
|
|
2212
|
+
isMediaEditableBinding(candidateBinding)));
|
|
2213
|
+
})
|
|
2214
|
+
.slice(0, 24);
|
|
2215
|
+
}
|
|
2216
|
+
isSdkChromeTarget(target) {
|
|
2217
|
+
if (!(target instanceof Node)) {
|
|
2218
|
+
return false;
|
|
2219
|
+
}
|
|
2220
|
+
return (!!this.hoverButtonContainer?.contains(target) ||
|
|
2221
|
+
!!this.quickFieldOverlayContainer?.contains(target) ||
|
|
2222
|
+
!!this.activeOutline?.contains(target) ||
|
|
2223
|
+
!!this.brandBadge?.contains(target) ||
|
|
2224
|
+
!!this.brandPopover?.contains(target) ||
|
|
2225
|
+
!!this.bottomBarHost?.contains(target) ||
|
|
2226
|
+
!!this.bottomBarMoreMenu?.contains(target));
|
|
1849
2227
|
}
|
|
1850
2228
|
findElementForBinding(binding) {
|
|
1851
2229
|
const selector = [
|
|
1852
2230
|
'[data-einblick-editable="true"]',
|
|
2231
|
+
`[data-einblick-source-type="${CSS.escape(binding.sourceType ?? 'cms')}"]`,
|
|
1853
2232
|
`[data-einblick-resource="${CSS.escape(binding.resourceSlug)}"]`,
|
|
1854
2233
|
`[data-einblick-record-id="${CSS.escape(binding.recordId)}"]`,
|
|
1855
2234
|
binding.fieldKey
|
|
@@ -1874,216 +2253,343 @@ class EinblickEditRuntime {
|
|
|
1874
2253
|
this.closeDrawer();
|
|
1875
2254
|
this.closeInlineEditor();
|
|
1876
2255
|
this.setActiveElement(null);
|
|
1877
|
-
const
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
gap: target.style.gap,
|
|
1889
|
-
minWidth: target.style.minWidth,
|
|
2256
|
+
const restoreState = {
|
|
2257
|
+
childNodes: Array.from(target.childNodes).map((node) => node.cloneNode(true)),
|
|
2258
|
+
contentEditable: target.getAttribute('contenteditable'),
|
|
2259
|
+
spellcheck: target.getAttribute('spellcheck'),
|
|
2260
|
+
tabIndex: target.tabIndex,
|
|
2261
|
+
hadTabIndex: target.hasAttribute('tabindex'),
|
|
2262
|
+
role: target.getAttribute('role'),
|
|
2263
|
+
ariaMultiline: target.getAttribute('aria-multiline'),
|
|
2264
|
+
title: target.getAttribute('title'),
|
|
2265
|
+
value: binding.value,
|
|
2266
|
+
cleanup: [],
|
|
1890
2267
|
};
|
|
2268
|
+
this.currentInlineRestoreState = restoreState;
|
|
1891
2269
|
target.dataset.einblickInlineEditing = 'true';
|
|
1892
|
-
target.
|
|
1893
|
-
target.
|
|
1894
|
-
target.
|
|
1895
|
-
target.
|
|
1896
|
-
target.
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
const errorMessage = document.createElement('div');
|
|
1908
|
-
errorMessage.setAttribute('data-einblick-inline-error', 'true');
|
|
1909
|
-
errorMessage.hidden = true;
|
|
1910
|
-
const actions = document.createElement('div');
|
|
1911
|
-
actions.setAttribute('data-einblick-inline-actions', 'true');
|
|
1912
|
-
const cancelButton = document.createElement('button');
|
|
1913
|
-
cancelButton.type = 'button';
|
|
1914
|
-
cancelButton.textContent = this.messages.actions.cancel;
|
|
1915
|
-
cancelButton.setAttribute('data-einblick-edit-action', 'secondary');
|
|
1916
|
-
cancelButton.addEventListener('click', () => this.closeInlineEditor());
|
|
1917
|
-
const saveButton = document.createElement('button');
|
|
1918
|
-
saveButton.type = 'button';
|
|
1919
|
-
saveButton.textContent = this.messages.actions.save;
|
|
1920
|
-
saveButton.setAttribute('data-einblick-edit-action', 'primary');
|
|
1921
|
-
const runSave = async () => {
|
|
1922
|
-
errorMessage.hidden = true;
|
|
1923
|
-
errorMessage.textContent = '';
|
|
1924
|
-
saveButton.disabled = true;
|
|
1925
|
-
saveButton.textContent = this.messages.actions.saving;
|
|
1926
|
-
cancelButton.disabled = true;
|
|
1927
|
-
try {
|
|
1928
|
-
const nextValue = this.getControlValue(control, binding);
|
|
1929
|
-
const savedValue = await this.saveInlineField(binding, nextValue);
|
|
1930
|
-
this.closeInlineEditor();
|
|
1931
|
-
this.applyValueToElement(target, binding, savedValue);
|
|
1932
|
-
await this.callbacks.onSave?.({
|
|
1933
|
-
binding,
|
|
1934
|
-
value: savedValue,
|
|
1935
|
-
source: 'inline',
|
|
1936
|
-
});
|
|
1937
|
-
}
|
|
1938
|
-
catch (error) {
|
|
1939
|
-
errorMessage.hidden = false;
|
|
1940
|
-
errorMessage.textContent =
|
|
1941
|
-
error instanceof Error
|
|
1942
|
-
? error.message
|
|
1943
|
-
: this.messages.errors.saveFieldFailed;
|
|
1944
|
-
saveButton.disabled = false;
|
|
1945
|
-
saveButton.textContent = this.messages.actions.save;
|
|
1946
|
-
cancelButton.disabled = false;
|
|
1947
|
-
}
|
|
2270
|
+
target.setAttribute('contenteditable', 'plaintext-only');
|
|
2271
|
+
target.setAttribute('spellcheck', 'true');
|
|
2272
|
+
target.setAttribute('role', 'textbox');
|
|
2273
|
+
target.setAttribute('aria-multiline', fieldTypeAllowsMultiline(binding) ? 'true' : 'false');
|
|
2274
|
+
if (!target.hasAttribute('tabindex')) {
|
|
2275
|
+
target.tabIndex = 0;
|
|
2276
|
+
}
|
|
2277
|
+
if ((target.textContent ?? '').trim().length === 0 &&
|
|
2278
|
+
binding.value !== undefined &&
|
|
2279
|
+
binding.value !== null) {
|
|
2280
|
+
target.textContent = formatValueForText(binding.value);
|
|
2281
|
+
}
|
|
2282
|
+
const handleClick = (event) => {
|
|
2283
|
+
event.preventDefault();
|
|
2284
|
+
event.stopPropagation();
|
|
1948
2285
|
};
|
|
1949
|
-
|
|
1950
|
-
void runSave();
|
|
1951
|
-
});
|
|
1952
|
-
control.addEventListener('keydown', (event) => {
|
|
1953
|
-
const keyboardEvent = event;
|
|
2286
|
+
const handleKeyDown = (keyboardEvent) => {
|
|
1954
2287
|
if (keyboardEvent.key === 'Escape') {
|
|
1955
2288
|
keyboardEvent.preventDefault();
|
|
2289
|
+
keyboardEvent.stopPropagation();
|
|
1956
2290
|
this.closeInlineEditor();
|
|
1957
2291
|
return;
|
|
1958
2292
|
}
|
|
1959
2293
|
if (keyboardEvent.key === 'Enter' &&
|
|
1960
|
-
(!(
|
|
2294
|
+
(!fieldTypeAllowsMultiline(binding) ||
|
|
1961
2295
|
keyboardEvent.metaKey ||
|
|
1962
2296
|
keyboardEvent.ctrlKey)) {
|
|
1963
2297
|
keyboardEvent.preventDefault();
|
|
1964
|
-
|
|
2298
|
+
keyboardEvent.stopPropagation();
|
|
2299
|
+
void this.commitInlineEditor();
|
|
2300
|
+
return;
|
|
1965
2301
|
}
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2302
|
+
if (isTextInputEvent(keyboardEvent)) {
|
|
2303
|
+
keyboardEvent.stopPropagation();
|
|
2304
|
+
}
|
|
2305
|
+
};
|
|
2306
|
+
const handlePaste = (event) => {
|
|
2307
|
+
const text = event.clipboardData?.getData('text/plain');
|
|
2308
|
+
if (text === undefined) {
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
event.preventDefault();
|
|
2312
|
+
event.stopPropagation();
|
|
2313
|
+
this.insertPlainTextAtSelection(text);
|
|
2314
|
+
};
|
|
2315
|
+
const handleBlur = () => {
|
|
2316
|
+
window.setTimeout(() => {
|
|
2317
|
+
if (this.currentInlineTarget === target) {
|
|
2318
|
+
void this.commitInlineEditor();
|
|
2319
|
+
}
|
|
2320
|
+
}, 0);
|
|
2321
|
+
};
|
|
2322
|
+
target.addEventListener('click', handleClick, true);
|
|
2323
|
+
target.addEventListener('keydown', handleKeyDown, true);
|
|
2324
|
+
target.addEventListener('paste', handlePaste, true);
|
|
2325
|
+
target.addEventListener('blur', handleBlur, true);
|
|
2326
|
+
restoreState.cleanup.push(() => target.removeEventListener('click', handleClick, true), () => target.removeEventListener('keydown', handleKeyDown, true), () => target.removeEventListener('paste', handlePaste, true), () => target.removeEventListener('blur', handleBlur, true));
|
|
1971
2327
|
this.currentInlineTarget = target;
|
|
1972
2328
|
this.currentInlineBinding = binding;
|
|
2329
|
+
this.ensureActiveOutline();
|
|
2330
|
+
this.activeOutline?.setAttribute('data-einblick-inline-active', 'true');
|
|
2331
|
+
this.positionOutline(this.activeOutline, target);
|
|
1973
2332
|
window.setTimeout(() => {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
}
|
|
2333
|
+
target.focus({ preventScroll: true });
|
|
2334
|
+
this.placeCaretAtEnd(target);
|
|
1977
2335
|
}, 0);
|
|
1978
2336
|
}
|
|
1979
|
-
closeInlineEditor() {
|
|
2337
|
+
closeInlineEditor(options = {}) {
|
|
2338
|
+
const restore = options.restore ?? true;
|
|
1980
2339
|
if (this.currentInlineTarget && this.currentInlineRestoreState) {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
this.currentInlineRestoreState.
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
this.currentInlineTarget.
|
|
1990
|
-
this.currentInlineRestoreState.minWidth;
|
|
2340
|
+
for (const cleanup of this.currentInlineRestoreState.cleanup) {
|
|
2341
|
+
cleanup();
|
|
2342
|
+
}
|
|
2343
|
+
if (restore) {
|
|
2344
|
+
this.currentInlineTarget.replaceChildren(...this.currentInlineRestoreState.childNodes.map((node) => node.cloneNode(true)));
|
|
2345
|
+
this.currentInlineTarget.dataset.einblickValue =
|
|
2346
|
+
serializeBindingValue(this.currentInlineRestoreState.value) ?? '';
|
|
2347
|
+
}
|
|
2348
|
+
this.restoreInlineTargetAttributes(this.currentInlineTarget, this.currentInlineRestoreState);
|
|
1991
2349
|
delete this.currentInlineTarget.dataset.einblickInlineEditing;
|
|
2350
|
+
delete this.currentInlineTarget.dataset.einblickInlineState;
|
|
2351
|
+
this.currentInlineTarget.removeAttribute('aria-busy');
|
|
1992
2352
|
}
|
|
1993
2353
|
this.currentInlineRestoreState = null;
|
|
1994
2354
|
this.currentInlineTarget = null;
|
|
1995
2355
|
this.currentInlineBinding = null;
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
const textarea = document.createElement('textarea');
|
|
2002
|
-
textarea.setAttribute('data-einblick-inline-textarea', 'true');
|
|
2003
|
-
return textarea;
|
|
2004
|
-
}
|
|
2005
|
-
case 'boolean': {
|
|
2006
|
-
const select = document.createElement('select');
|
|
2007
|
-
select.setAttribute('data-einblick-inline-select', 'true');
|
|
2008
|
-
const trueOption = document.createElement('option');
|
|
2009
|
-
trueOption.value = 'true';
|
|
2010
|
-
trueOption.textContent = this.messages.values.true;
|
|
2011
|
-
const falseOption = document.createElement('option');
|
|
2012
|
-
falseOption.value = 'false';
|
|
2013
|
-
falseOption.textContent = this.messages.values.false;
|
|
2014
|
-
select.append(trueOption, falseOption);
|
|
2015
|
-
return select;
|
|
2016
|
-
}
|
|
2017
|
-
default: {
|
|
2018
|
-
const textValue = typeof binding.value === 'string'
|
|
2019
|
-
? binding.value
|
|
2020
|
-
: (target?.textContent ?? '');
|
|
2021
|
-
if (binding.fieldType === 'string' &&
|
|
2022
|
-
typeof textValue === 'string' &&
|
|
2023
|
-
textValue.includes('\n')) {
|
|
2024
|
-
const textarea = document.createElement('textarea');
|
|
2025
|
-
textarea.setAttribute('data-einblick-inline-textarea', 'true');
|
|
2026
|
-
return textarea;
|
|
2027
|
-
}
|
|
2028
|
-
const input = document.createElement('input');
|
|
2029
|
-
input.setAttribute('data-einblick-inline-control', 'true');
|
|
2030
|
-
if (binding.fieldType === 'number') {
|
|
2031
|
-
input.type = 'number';
|
|
2032
|
-
}
|
|
2033
|
-
else if (binding.fieldType === 'date') {
|
|
2034
|
-
input.type = 'date';
|
|
2035
|
-
}
|
|
2036
|
-
else {
|
|
2037
|
-
input.type = 'text';
|
|
2038
|
-
}
|
|
2039
|
-
return input;
|
|
2040
|
-
}
|
|
2356
|
+
this.inlineSaveInFlight = null;
|
|
2357
|
+
this.activeOutline?.removeAttribute('data-einblick-inline-active');
|
|
2358
|
+
if (!this.activeElement) {
|
|
2359
|
+
this.activeOutline?.remove();
|
|
2360
|
+
this.activeOutline = null;
|
|
2041
2361
|
}
|
|
2042
2362
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
control.value = currentValue === true ? 'true' : 'false';
|
|
2047
|
-
return;
|
|
2363
|
+
restoreInlineTargetAttributes(target, restoreState) {
|
|
2364
|
+
if (restoreState.contentEditable === null) {
|
|
2365
|
+
target.removeAttribute('contenteditable');
|
|
2048
2366
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
? currentValue
|
|
2052
|
-
.map((entry) => (typeof entry === 'string' ? entry : String(entry)))
|
|
2053
|
-
.join(', ')
|
|
2054
|
-
: currentValue === undefined || currentValue === null
|
|
2055
|
-
? ''
|
|
2056
|
-
: String(currentValue);
|
|
2057
|
-
return;
|
|
2367
|
+
else {
|
|
2368
|
+
target.setAttribute('contenteditable', restoreState.contentEditable);
|
|
2058
2369
|
}
|
|
2059
|
-
if (
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2370
|
+
if (restoreState.spellcheck === null) {
|
|
2371
|
+
target.removeAttribute('spellcheck');
|
|
2372
|
+
}
|
|
2373
|
+
else {
|
|
2374
|
+
target.setAttribute('spellcheck', restoreState.spellcheck);
|
|
2375
|
+
}
|
|
2376
|
+
if (restoreState.role === null) {
|
|
2377
|
+
target.removeAttribute('role');
|
|
2378
|
+
}
|
|
2379
|
+
else {
|
|
2380
|
+
target.setAttribute('role', restoreState.role);
|
|
2381
|
+
}
|
|
2382
|
+
if (restoreState.ariaMultiline === null) {
|
|
2383
|
+
target.removeAttribute('aria-multiline');
|
|
2384
|
+
}
|
|
2385
|
+
else {
|
|
2386
|
+
target.setAttribute('aria-multiline', restoreState.ariaMultiline);
|
|
2387
|
+
}
|
|
2388
|
+
if (restoreState.title === null) {
|
|
2389
|
+
target.removeAttribute('title');
|
|
2390
|
+
}
|
|
2391
|
+
else {
|
|
2392
|
+
target.setAttribute('title', restoreState.title);
|
|
2393
|
+
}
|
|
2394
|
+
if (restoreState.hadTabIndex) {
|
|
2395
|
+
target.tabIndex = restoreState.tabIndex;
|
|
2396
|
+
}
|
|
2397
|
+
else {
|
|
2398
|
+
target.removeAttribute('tabindex');
|
|
2063
2399
|
}
|
|
2064
|
-
control.value =
|
|
2065
|
-
currentValue === undefined || currentValue === null
|
|
2066
|
-
? ''
|
|
2067
|
-
: typeof currentValue === 'string'
|
|
2068
|
-
? currentValue
|
|
2069
|
-
: String(currentValue);
|
|
2070
2400
|
}
|
|
2071
|
-
|
|
2072
|
-
const rawValue =
|
|
2401
|
+
getInlineEditableValue(target, binding) {
|
|
2402
|
+
const rawValue = fieldTypeAllowsMultiline(binding)
|
|
2403
|
+
? target.innerText.replace(/\n$/, '')
|
|
2404
|
+
: (target.textContent ?? '').replace(/\s+/g, ' ').trim();
|
|
2073
2405
|
switch (binding.fieldType) {
|
|
2074
2406
|
case 'number':
|
|
2075
2407
|
return rawValue.trim().length === 0 ? null : Number(rawValue);
|
|
2076
|
-
case 'boolean':
|
|
2077
|
-
return rawValue === 'true';
|
|
2078
2408
|
case 'tags':
|
|
2079
2409
|
return rawValue
|
|
2080
2410
|
.split(',')
|
|
2081
2411
|
.map((entry) => entry.trim())
|
|
2082
2412
|
.filter(Boolean);
|
|
2413
|
+
case 'date':
|
|
2414
|
+
return normalizeDateValue(rawValue.trim());
|
|
2083
2415
|
default:
|
|
2084
2416
|
return rawValue;
|
|
2085
2417
|
}
|
|
2086
2418
|
}
|
|
2419
|
+
async commitInlineEditor() {
|
|
2420
|
+
if (this.inlineSaveInFlight) {
|
|
2421
|
+
return await this.inlineSaveInFlight;
|
|
2422
|
+
}
|
|
2423
|
+
const target = this.currentInlineTarget;
|
|
2424
|
+
const binding = this.currentInlineBinding;
|
|
2425
|
+
if (!target || !binding) {
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
this.inlineSaveInFlight = (async () => {
|
|
2429
|
+
target.setAttribute('aria-busy', 'true');
|
|
2430
|
+
target.dataset.einblickInlineState = 'saving';
|
|
2431
|
+
try {
|
|
2432
|
+
const nextValue = this.getInlineEditableValue(target, binding);
|
|
2433
|
+
const savedValue = await this.saveInlineField(binding, nextValue);
|
|
2434
|
+
this.closeInlineEditor({ restore: false });
|
|
2435
|
+
this.applyValueToElement(target, binding, savedValue);
|
|
2436
|
+
await this.callbacks.onSave?.({
|
|
2437
|
+
binding,
|
|
2438
|
+
value: savedValue,
|
|
2439
|
+
source: 'inline',
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
catch (error) {
|
|
2443
|
+
target.dataset.einblickInlineState = 'error';
|
|
2444
|
+
target.removeAttribute('aria-busy');
|
|
2445
|
+
this.inlineSaveInFlight = null;
|
|
2446
|
+
const message = error instanceof Error
|
|
2447
|
+
? error.message
|
|
2448
|
+
: this.messages.errors.saveFieldFailed;
|
|
2449
|
+
target.title = message;
|
|
2450
|
+
this.callbacks.onError?.(message);
|
|
2451
|
+
}
|
|
2452
|
+
})();
|
|
2453
|
+
await this.inlineSaveInFlight;
|
|
2454
|
+
}
|
|
2455
|
+
insertPlainTextAtSelection(text) {
|
|
2456
|
+
const selection = window.getSelection();
|
|
2457
|
+
if (!selection || selection.rangeCount === 0) {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
selection.deleteFromDocument();
|
|
2461
|
+
selection.getRangeAt(0).insertNode(document.createTextNode(text));
|
|
2462
|
+
selection.collapseToEnd();
|
|
2463
|
+
}
|
|
2464
|
+
placeCaretAtEnd(target) {
|
|
2465
|
+
const selection = window.getSelection();
|
|
2466
|
+
if (!selection) {
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
const range = document.createRange();
|
|
2470
|
+
range.selectNodeContents(target);
|
|
2471
|
+
range.collapse(false);
|
|
2472
|
+
selection.removeAllRanges();
|
|
2473
|
+
selection.addRange(range);
|
|
2474
|
+
}
|
|
2475
|
+
openMediaPicker(target, binding, button) {
|
|
2476
|
+
if (!this.state.isAuthenticated) {
|
|
2477
|
+
this.callbacks.onError?.(this.messages.errors.signInToEditField);
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
if (!binding.fieldKey) {
|
|
2481
|
+
this.callbacks.onError?.(this.messages.errors.fieldBindingRequired);
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2484
|
+
const input = document.createElement('input');
|
|
2485
|
+
input.type = 'file';
|
|
2486
|
+
input.accept = getMediaAcceptValue(binding);
|
|
2487
|
+
input.style.position = 'fixed';
|
|
2488
|
+
input.style.left = '-9999px';
|
|
2489
|
+
input.style.top = '0';
|
|
2490
|
+
const previousText = button?.textContent ?? '';
|
|
2491
|
+
const resetButton = () => {
|
|
2492
|
+
if (button) {
|
|
2493
|
+
button.disabled = false;
|
|
2494
|
+
button.textContent =
|
|
2495
|
+
previousText || getMediaActionLabel(binding, this.messages);
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
input.addEventListener('change', () => {
|
|
2499
|
+
const file = input.files?.[0];
|
|
2500
|
+
input.remove();
|
|
2501
|
+
if (!file) {
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
if (button) {
|
|
2505
|
+
button.disabled = true;
|
|
2506
|
+
button.textContent = this.messages.actions.uploading;
|
|
2507
|
+
}
|
|
2508
|
+
void (async () => {
|
|
2509
|
+
try {
|
|
2510
|
+
const result = await this.saveInlineMediaField(binding, file);
|
|
2511
|
+
this.applyMediaPreviewToElement(target, file);
|
|
2512
|
+
await this.callbacks.onSave?.({
|
|
2513
|
+
binding,
|
|
2514
|
+
value: result.value,
|
|
2515
|
+
source: 'inline',
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
catch (error) {
|
|
2519
|
+
const message = error instanceof Error
|
|
2520
|
+
? error.message
|
|
2521
|
+
: this.messages.errors.saveFieldFailed;
|
|
2522
|
+
this.callbacks.onError?.(message);
|
|
2523
|
+
}
|
|
2524
|
+
finally {
|
|
2525
|
+
resetButton();
|
|
2526
|
+
}
|
|
2527
|
+
})();
|
|
2528
|
+
});
|
|
2529
|
+
input.addEventListener('cancel', () => {
|
|
2530
|
+
input.remove();
|
|
2531
|
+
});
|
|
2532
|
+
document.body.append(input);
|
|
2533
|
+
input.click();
|
|
2534
|
+
}
|
|
2535
|
+
async saveInlineMediaField(binding, file) {
|
|
2536
|
+
if (!this.bridgeFrame?.contentWindow) {
|
|
2537
|
+
throw new Error(this.messages.errors.bridgeNotConnected);
|
|
2538
|
+
}
|
|
2539
|
+
if (!this.state.isAuthenticated) {
|
|
2540
|
+
throw new Error(this.messages.errors.signInToEditField);
|
|
2541
|
+
}
|
|
2542
|
+
if (!binding.fieldKey) {
|
|
2543
|
+
throw new Error(this.messages.errors.fieldBindingRequired);
|
|
2544
|
+
}
|
|
2545
|
+
const requestId = createRandomId();
|
|
2546
|
+
const promise = new Promise((resolve, reject) => {
|
|
2547
|
+
const timeoutId = window.setTimeout(() => {
|
|
2548
|
+
this.pendingInlineMediaSaves.delete(requestId);
|
|
2549
|
+
reject(new Error(this.messages.errors.savingTimedOut));
|
|
2550
|
+
}, 60000);
|
|
2551
|
+
this.pendingInlineMediaSaves.set(requestId, {
|
|
2552
|
+
resolve,
|
|
2553
|
+
reject,
|
|
2554
|
+
timeoutId,
|
|
2555
|
+
});
|
|
2556
|
+
});
|
|
2557
|
+
this.bridgeFrame.contentWindow.postMessage({
|
|
2558
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
2559
|
+
type: 'replace-inline-media',
|
|
2560
|
+
nonce: this.bridgeNonce,
|
|
2561
|
+
requestId,
|
|
2562
|
+
payload: {
|
|
2563
|
+
sourceType: binding.sourceType ?? 'cms',
|
|
2564
|
+
resourceSlug: binding.resourceSlug,
|
|
2565
|
+
recordId: binding.recordId,
|
|
2566
|
+
fieldKey: binding.fieldKey,
|
|
2567
|
+
file,
|
|
2568
|
+
},
|
|
2569
|
+
}, this.appOrigin);
|
|
2570
|
+
return await promise;
|
|
2571
|
+
}
|
|
2572
|
+
applyMediaPreviewToElement(element, file) {
|
|
2573
|
+
if (!file.type.startsWith('image/')) {
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
const image = element instanceof HTMLImageElement
|
|
2577
|
+
? element
|
|
2578
|
+
: element.querySelector('img');
|
|
2579
|
+
if (!image) {
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
const objectUrl = URL.createObjectURL(file);
|
|
2583
|
+
const previousUrl = image.src;
|
|
2584
|
+
image.addEventListener('load', () => {
|
|
2585
|
+
URL.revokeObjectURL(objectUrl);
|
|
2586
|
+
}, { once: true });
|
|
2587
|
+
image.addEventListener('error', () => {
|
|
2588
|
+
image.src = previousUrl;
|
|
2589
|
+
URL.revokeObjectURL(objectUrl);
|
|
2590
|
+
}, { once: true });
|
|
2591
|
+
image.src = objectUrl;
|
|
2592
|
+
}
|
|
2087
2593
|
async saveInlineField(binding, value) {
|
|
2088
2594
|
if (!this.bridgeFrame?.contentWindow) {
|
|
2089
2595
|
throw new Error(this.messages.errors.bridgeNotConnected);
|
|
@@ -2108,6 +2614,7 @@ class EinblickEditRuntime {
|
|
|
2108
2614
|
nonce: this.bridgeNonce,
|
|
2109
2615
|
requestId,
|
|
2110
2616
|
payload: {
|
|
2617
|
+
sourceType: binding.sourceType ?? 'cms',
|
|
2111
2618
|
resourceSlug: binding.resourceSlug,
|
|
2112
2619
|
recordId: binding.recordId,
|
|
2113
2620
|
fieldKey: binding.fieldKey,
|
|
@@ -2176,6 +2683,8 @@ class EinblickEditRuntime {
|
|
|
2176
2683
|
nonce,
|
|
2177
2684
|
intent: args.intent,
|
|
2178
2685
|
recordId: args.recordId,
|
|
2686
|
+
sourceType: args.sourceType,
|
|
2687
|
+
resourceSlug: args.resourceSlug,
|
|
2179
2688
|
});
|
|
2180
2689
|
}
|
|
2181
2690
|
catch (error) {
|
|
@@ -2188,6 +2697,7 @@ class EinblickEditRuntime {
|
|
|
2188
2697
|
this.editorTarget = null;
|
|
2189
2698
|
this.editorBinding = args.resourceSlug
|
|
2190
2699
|
? {
|
|
2700
|
+
sourceType: args.sourceType ?? 'cms',
|
|
2191
2701
|
resourceSlug: args.resourceSlug,
|
|
2192
2702
|
recordId: args.recordId ?? '',
|
|
2193
2703
|
resourceMode: 'collection',
|
|
@@ -2259,6 +2769,7 @@ export function createEinblickEditRuntime(options) {
|
|
|
2259
2769
|
login: (loginOptions) => runtime.login(loginOptions),
|
|
2260
2770
|
openEditor: (binding, element) => runtime.openEditor(binding, element),
|
|
2261
2771
|
setLocale: (locale) => runtime.setLocale(locale),
|
|
2772
|
+
setResourceHints: (hints) => runtime.setResourceHints(hints),
|
|
2262
2773
|
};
|
|
2263
2774
|
}
|
|
2264
2775
|
//# sourceMappingURL=runtime.js.map
|