@einblick/sdk 0.6.4 → 0.7.2
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/AGENTS.md +1 -1
- package/README.md +61 -13
- package/dist/cli.js +1 -7
- package/dist/cli.js.map +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +63 -11
- package/dist/codegen.js.map +1 -1
- package/dist/next/edit-boot.d.ts +10 -19
- package/dist/next/edit-boot.d.ts.map +1 -1
- package/dist/next/edit-boot.js +14 -28
- package/dist/next/edit-boot.js.map +1 -1
- package/dist/next/revalidate.d.ts +4 -2
- package/dist/next/revalidate.d.ts.map +1 -1
- package/dist/next/revalidate.js +46 -12
- package/dist/next/revalidate.js.map +1 -1
- package/dist/react/markers.d.ts +5 -1
- package/dist/react/markers.d.ts.map +1 -1
- package/dist/react/markers.js +23 -6
- package/dist/react/markers.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 +17 -3
- package/dist/react/provider.js.map +1 -1
- package/dist/react/runtime.d.ts +5 -0
- package/dist/react/runtime.d.ts.map +1 -1
- package/dist/react/runtime.js +396 -147
- package/dist/react/runtime.js.map +1 -1
- package/dist/react/shared.d.ts.map +1 -1
- package/dist/react/shared.js +10 -12
- package/dist/react/shared.js.map +1 -1
- package/dist/react/types.d.ts +3 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/types.js.map +1 -1
- package/package.json +9 -12
- package/dist/client.test.d.ts +0 -2
- package/dist/client.test.d.ts.map +0 -1
- package/dist/client.test.js +0 -342
- package/dist/client.test.js.map +0 -1
- package/dist/codegen.test.d.ts +0 -2
- package/dist/codegen.test.d.ts.map +0 -1
- package/dist/codegen.test.js +0 -219
- package/dist/codegen.test.js.map +0 -1
package/dist/react/runtime.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
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
3
|
const RUNTIME_STYLE_ID = 'einblick-edit-runtime-styles';
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const DEFAULT_EINBLICK_ACCENT_COLOR = 'rgb(250, 105, 62)';
|
|
5
|
+
const EINBLICK_ACCENT_COLOR_VAR = '--einblick-editor-accent-color';
|
|
6
|
+
const EINBLICK_ACCENT_COLOR = `var(${EINBLICK_ACCENT_COLOR_VAR}, ${DEFAULT_EINBLICK_ACCENT_COLOR})`;
|
|
7
|
+
const EINBLICK_ACCENT_TINT = `color-mix(in srgb, ${EINBLICK_ACCENT_COLOR} 12%, transparent)`;
|
|
8
|
+
const EINBLICK_ACCENT_HOVER_COLOR = `color-mix(in srgb, ${EINBLICK_ACCENT_COLOR} 92%, black)`;
|
|
7
9
|
const CONTROL_BAR_HEIGHT = 44;
|
|
8
10
|
function getBrandBadgeSvg(size) {
|
|
9
11
|
return `
|
|
@@ -40,12 +42,40 @@ function getMoreActionsSvg(size) {
|
|
|
40
42
|
</svg>
|
|
41
43
|
`;
|
|
42
44
|
}
|
|
45
|
+
function createDatabaseIconElement(size) {
|
|
46
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
47
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
48
|
+
svg.setAttribute('width', String(size));
|
|
49
|
+
svg.setAttribute('height', String(size));
|
|
50
|
+
svg.setAttribute('fill', 'none');
|
|
51
|
+
svg.setAttribute('stroke', 'currentColor');
|
|
52
|
+
svg.setAttribute('stroke-width', '2');
|
|
53
|
+
svg.setAttribute('stroke-linecap', 'round');
|
|
54
|
+
svg.setAttribute('stroke-linejoin', 'round');
|
|
55
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
56
|
+
svg.setAttribute('focusable', 'false');
|
|
57
|
+
const ellipse = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse');
|
|
58
|
+
ellipse.setAttribute('cx', '12');
|
|
59
|
+
ellipse.setAttribute('cy', '5');
|
|
60
|
+
ellipse.setAttribute('rx', '9');
|
|
61
|
+
ellipse.setAttribute('ry', '3');
|
|
62
|
+
const sidePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
63
|
+
sidePath.setAttribute('d', 'M3 5V19A9 3 0 0 0 21 19V5');
|
|
64
|
+
const middlePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
65
|
+
middlePath.setAttribute('d', 'M3 12A9 3 0 0 0 21 12');
|
|
66
|
+
svg.append(ellipse, sidePath, middlePath);
|
|
67
|
+
return svg;
|
|
68
|
+
}
|
|
43
69
|
function createRandomId() {
|
|
44
|
-
if (typeof crypto
|
|
45
|
-
|
|
70
|
+
if (typeof crypto === 'undefined') {
|
|
71
|
+
throw new Error('Secure browser randomness is unavailable');
|
|
72
|
+
}
|
|
73
|
+
if (typeof crypto.randomUUID === 'function') {
|
|
46
74
|
return crypto.randomUUID();
|
|
47
75
|
}
|
|
48
|
-
|
|
76
|
+
const bytes = new Uint8Array(16);
|
|
77
|
+
crypto.getRandomValues(bytes);
|
|
78
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
49
79
|
}
|
|
50
80
|
function stopEvent(event) {
|
|
51
81
|
event.preventDefault();
|
|
@@ -54,6 +84,24 @@ function stopEvent(event) {
|
|
|
54
84
|
function clamp(value, min, max) {
|
|
55
85
|
return Math.min(Math.max(value, min), max);
|
|
56
86
|
}
|
|
87
|
+
function rectsOverlap(first, second, padding = 0) {
|
|
88
|
+
return (first.left < second.right + padding &&
|
|
89
|
+
first.right > second.left - padding &&
|
|
90
|
+
first.top < second.bottom + padding &&
|
|
91
|
+
first.bottom > second.top - padding);
|
|
92
|
+
}
|
|
93
|
+
function normalizeAccentColor(accentColor) {
|
|
94
|
+
const normalized = accentColor?.trim();
|
|
95
|
+
if (!normalized) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (typeof CSS !== 'undefined' &&
|
|
99
|
+
typeof CSS.supports === 'function' &&
|
|
100
|
+
!CSS.supports('color', normalized)) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
57
105
|
function isTextInputEvent(event) {
|
|
58
106
|
return (event.key.length === 1 ||
|
|
59
107
|
event.key === 'Enter' ||
|
|
@@ -67,15 +115,37 @@ function fieldTypeAllowsMultiline(binding) {
|
|
|
67
115
|
return binding.fieldType === 'text' || binding.fieldType === 'markdown';
|
|
68
116
|
}
|
|
69
117
|
function getMediaAcceptValue(binding) {
|
|
70
|
-
return binding.fieldType === 'image'
|
|
71
|
-
? 'image/*'
|
|
72
|
-
: '';
|
|
118
|
+
return binding.fieldType === 'image' ? 'image/*' : '';
|
|
73
119
|
}
|
|
74
120
|
function getMediaActionLabel(binding, messages) {
|
|
75
|
-
return binding.fieldType === 'image'
|
|
121
|
+
return binding.fieldType === 'image'
|
|
76
122
|
? messages.actions.replaceImage
|
|
77
123
|
: messages.actions.replaceFile;
|
|
78
124
|
}
|
|
125
|
+
function isMultiMediaBinding(binding) {
|
|
126
|
+
return binding?.fieldType === 'images' || binding?.fieldType === 'files';
|
|
127
|
+
}
|
|
128
|
+
function setOverlayButtonContent(button, label, options) {
|
|
129
|
+
const hasDatabaseIcon = options?.databaseIcon === true;
|
|
130
|
+
if (button.dataset.einblickOverlayButtonLabel === label &&
|
|
131
|
+
button.dataset.einblickOverlayButtonDatabaseIcon ===
|
|
132
|
+
(hasDatabaseIcon ? 'true' : 'false')) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const text = document.createElement('span');
|
|
136
|
+
text.setAttribute('data-einblick-overlay-button-label', 'true');
|
|
137
|
+
text.textContent = label;
|
|
138
|
+
button.replaceChildren();
|
|
139
|
+
if (hasDatabaseIcon) {
|
|
140
|
+
button.append(createDatabaseIconElement(14));
|
|
141
|
+
}
|
|
142
|
+
button.append(text);
|
|
143
|
+
button.title = label;
|
|
144
|
+
button.dataset.einblickOverlayButtonLabel = label;
|
|
145
|
+
button.dataset.einblickOverlayButtonDatabaseIcon = hasDatabaseIcon
|
|
146
|
+
? 'true'
|
|
147
|
+
: 'false';
|
|
148
|
+
}
|
|
79
149
|
function injectRuntimeStyles() {
|
|
80
150
|
if (typeof document === 'undefined') {
|
|
81
151
|
return;
|
|
@@ -91,13 +161,12 @@ function injectRuntimeStyles() {
|
|
|
91
161
|
}
|
|
92
162
|
|
|
93
163
|
[data-einblick-editable="true"][data-einblick-hover-active="true"] {
|
|
94
|
-
outline: 1px solid ${
|
|
164
|
+
outline: 1px solid ${EINBLICK_ACCENT_COLOR};
|
|
95
165
|
outline-offset: -1px;
|
|
96
|
-
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.72);
|
|
97
166
|
}
|
|
98
167
|
|
|
99
168
|
[data-einblick-editable="true"][data-einblick-field-hover-active="true"] {
|
|
100
|
-
outline: 1px dashed
|
|
169
|
+
outline: 1px dashed ${EINBLICK_ACCENT_COLOR};
|
|
101
170
|
outline-offset: -1px;
|
|
102
171
|
}
|
|
103
172
|
|
|
@@ -111,43 +180,46 @@ function injectRuntimeStyles() {
|
|
|
111
180
|
z-index: 2147483644;
|
|
112
181
|
display: inline-flex;
|
|
113
182
|
align-items: center;
|
|
114
|
-
gap: 0;
|
|
183
|
+
gap: 0.25rem;
|
|
115
184
|
}
|
|
116
185
|
|
|
117
186
|
[data-einblick-edit-button],
|
|
118
|
-
[data-einblick-create-button],
|
|
187
|
+
[data-einblick-collection-create-button],
|
|
119
188
|
[data-einblick-field-button] {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
gap: 0.35rem;
|
|
120
193
|
border: 1px solid ${EINBLICK_ACCENT_COLOR};
|
|
121
194
|
border-radius: 0;
|
|
122
|
-
min-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.16);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
[data-einblick-edit-button],
|
|
131
|
-
[data-einblick-field-button="media"] {
|
|
195
|
+
min-width: max-content;
|
|
196
|
+
min-height: 2.05rem;
|
|
197
|
+
max-width: calc(100vw - 0.5rem);
|
|
198
|
+
padding: 0 0.74rem;
|
|
199
|
+
overflow: hidden;
|
|
132
200
|
background: ${EINBLICK_ACCENT_COLOR};
|
|
133
201
|
color: rgb(255, 255, 255);
|
|
202
|
+
font: 700 13px/1 system-ui, sans-serif;
|
|
203
|
+
letter-spacing: 0;
|
|
204
|
+
white-space: nowrap;
|
|
205
|
+
text-overflow: ellipsis;
|
|
206
|
+
cursor: pointer;
|
|
134
207
|
}
|
|
135
208
|
|
|
136
|
-
[data-einblick-edit-button]
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
background: rgb(255, 255, 255);
|
|
143
|
-
color: ${EINBLICK_ACCENT_COLOR};
|
|
209
|
+
[data-einblick-edit-button] svg,
|
|
210
|
+
[data-einblick-collection-create-button] svg,
|
|
211
|
+
[data-einblick-field-button] svg {
|
|
212
|
+
flex: none;
|
|
213
|
+
width: 0.95rem;
|
|
214
|
+
height: 0.95rem;
|
|
144
215
|
}
|
|
145
216
|
|
|
146
217
|
[data-einblick-edit-button]:hover,
|
|
147
|
-
[data-einblick-create-button]:hover,
|
|
218
|
+
[data-einblick-collection-create-button]:hover,
|
|
148
219
|
[data-einblick-field-button]:hover {
|
|
149
|
-
background:
|
|
150
|
-
|
|
220
|
+
background: ${EINBLICK_ACCENT_COLOR};
|
|
221
|
+
background: ${EINBLICK_ACCENT_HOVER_COLOR};
|
|
222
|
+
color: rgb(255, 255, 255);
|
|
151
223
|
}
|
|
152
224
|
|
|
153
225
|
[data-einblick-field-overlays] {
|
|
@@ -162,8 +234,6 @@ function injectRuntimeStyles() {
|
|
|
162
234
|
position: absolute;
|
|
163
235
|
z-index: 2147483644;
|
|
164
236
|
pointer-events: auto;
|
|
165
|
-
font-size: 11px;
|
|
166
|
-
min-height: 1.65rem;
|
|
167
237
|
}
|
|
168
238
|
|
|
169
239
|
[data-einblick-brand-badge] {
|
|
@@ -182,17 +252,15 @@ function injectRuntimeStyles() {
|
|
|
182
252
|
background: transparent;
|
|
183
253
|
color: ${EINBLICK_ACCENT_COLOR};
|
|
184
254
|
cursor: pointer;
|
|
185
|
-
|
|
186
|
-
transition: transform 120ms ease, filter 120ms ease;
|
|
255
|
+
transition: transform 120ms ease;
|
|
187
256
|
}
|
|
188
257
|
|
|
189
258
|
[data-einblick-brand-badge]:hover {
|
|
190
259
|
transform: translateY(-1px) scale(1.04);
|
|
191
|
-
filter: drop-shadow(0 12px 28px rgba(15, 23, 42, 0.28));
|
|
192
260
|
}
|
|
193
261
|
|
|
194
262
|
[data-einblick-brand-badge]:focus-visible {
|
|
195
|
-
outline: 2px solid ${
|
|
263
|
+
outline: 2px solid ${EINBLICK_ACCENT_COLOR};
|
|
196
264
|
outline-offset: 4px;
|
|
197
265
|
border-radius: 999px;
|
|
198
266
|
}
|
|
@@ -212,7 +280,6 @@ function injectRuntimeStyles() {
|
|
|
212
280
|
color: rgb(15, 23, 42);
|
|
213
281
|
border-radius: 1.25rem;
|
|
214
282
|
padding: 1rem;
|
|
215
|
-
box-shadow: 0 22px 56px rgba(15, 23, 42, 0.2);
|
|
216
283
|
backdrop-filter: blur(18px);
|
|
217
284
|
box-sizing: border-box;
|
|
218
285
|
}
|
|
@@ -262,7 +329,8 @@ function injectRuntimeStyles() {
|
|
|
262
329
|
display: inline-flex;
|
|
263
330
|
align-items: center;
|
|
264
331
|
border-radius: 999px;
|
|
265
|
-
background:
|
|
332
|
+
background: transparent;
|
|
333
|
+
background: ${EINBLICK_ACCENT_TINT};
|
|
266
334
|
color: ${EINBLICK_ACCENT_COLOR};
|
|
267
335
|
padding: 0.32rem 0.58rem;
|
|
268
336
|
font: 600 0.74rem/1 system-ui, sans-serif;
|
|
@@ -311,7 +379,8 @@ function injectRuntimeStyles() {
|
|
|
311
379
|
|
|
312
380
|
[data-einblick-brand-popover-action="primary"]:hover {
|
|
313
381
|
border-color: ${EINBLICK_ACCENT_COLOR};
|
|
314
|
-
background:
|
|
382
|
+
background: ${EINBLICK_ACCENT_COLOR};
|
|
383
|
+
background: ${EINBLICK_ACCENT_HOVER_COLOR};
|
|
315
384
|
}
|
|
316
385
|
|
|
317
386
|
[data-einblick-inline-editing="true"] {
|
|
@@ -337,7 +406,6 @@ function injectRuntimeStyles() {
|
|
|
337
406
|
width: min(46rem, 100vw);
|
|
338
407
|
background: rgb(255, 255, 255);
|
|
339
408
|
border-left: 1px solid rgba(148, 163, 184, 0.35);
|
|
340
|
-
box-shadow: 0 24px 64px rgba(15, 23, 42, 0.26);
|
|
341
409
|
overflow: hidden;
|
|
342
410
|
}
|
|
343
411
|
|
|
@@ -359,7 +427,6 @@ function injectRuntimeStyles() {
|
|
|
359
427
|
border-top: 1px solid rgba(148, 163, 184, 0.36);
|
|
360
428
|
overflow: hidden;
|
|
361
429
|
background: rgb(255, 255, 255);
|
|
362
|
-
box-shadow: 0 -12px 28px rgba(15, 23, 42, 0.12);
|
|
363
430
|
pointer-events: none;
|
|
364
431
|
transform: translateY(100%);
|
|
365
432
|
transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
@@ -394,10 +461,14 @@ class EinblickEditRuntime {
|
|
|
394
461
|
callbacks;
|
|
395
462
|
chrome;
|
|
396
463
|
reserveBottomSpace;
|
|
464
|
+
persist;
|
|
397
465
|
locale;
|
|
398
466
|
messages;
|
|
467
|
+
accentColor;
|
|
468
|
+
originalRootAccentColor;
|
|
399
469
|
bridgeNonce = createRandomId();
|
|
400
470
|
session;
|
|
471
|
+
brokerId = null;
|
|
401
472
|
state = {
|
|
402
473
|
enabled: true,
|
|
403
474
|
active: true,
|
|
@@ -409,7 +480,6 @@ class EinblickEditRuntime {
|
|
|
409
480
|
activeElement = null;
|
|
410
481
|
hoverButtonContainer = null;
|
|
411
482
|
hoverButton = null;
|
|
412
|
-
hoverCreateButton = null;
|
|
413
483
|
quickFieldOverlayContainer = null;
|
|
414
484
|
quickFieldOverlays = [];
|
|
415
485
|
brandBadge = null;
|
|
@@ -436,6 +506,7 @@ class EinblickEditRuntime {
|
|
|
436
506
|
currentInlineRestoreState = null;
|
|
437
507
|
inlineSaveInFlight = null;
|
|
438
508
|
editorBackdrop = null;
|
|
509
|
+
editorFrame = null;
|
|
439
510
|
editorNonce = null;
|
|
440
511
|
editorTarget = null;
|
|
441
512
|
editorBinding = null;
|
|
@@ -453,8 +524,10 @@ class EinblickEditRuntime {
|
|
|
453
524
|
this.chrome = options.chrome ?? 'bar';
|
|
454
525
|
this.reserveBottomSpace =
|
|
455
526
|
options.reserveBottomSpace ?? this.chrome === 'bar';
|
|
527
|
+
this.persist = options.persist ?? true;
|
|
456
528
|
this.locale = resolveEinblickSdkLocale(options.locale);
|
|
457
529
|
this.messages = getEinblickSdkMessages(this.locale);
|
|
530
|
+
this.accentColor = normalizeAccentColor(options.accentColor);
|
|
458
531
|
this.session =
|
|
459
532
|
options.initialSession && !isEditSessionExpired(options.initialSession)
|
|
460
533
|
? options.initialSession
|
|
@@ -475,6 +548,43 @@ class EinblickEditRuntime {
|
|
|
475
548
|
this.messages = getEinblickSdkMessages(nextLocale);
|
|
476
549
|
this.refreshLocalizedUi();
|
|
477
550
|
}
|
|
551
|
+
setAccentColor(accentColor) {
|
|
552
|
+
const nextAccentColor = normalizeAccentColor(accentColor);
|
|
553
|
+
if (nextAccentColor === this.accentColor) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
this.accentColor = nextAccentColor;
|
|
557
|
+
this.applyAccentColor();
|
|
558
|
+
}
|
|
559
|
+
applyAccentColor() {
|
|
560
|
+
if (typeof document === 'undefined') {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (!this.accentColor) {
|
|
564
|
+
this.restoreAccentColor();
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const root = document.documentElement;
|
|
568
|
+
if (this.originalRootAccentColor === undefined) {
|
|
569
|
+
this.originalRootAccentColor =
|
|
570
|
+
root.style.getPropertyValue(EINBLICK_ACCENT_COLOR_VAR) || null;
|
|
571
|
+
}
|
|
572
|
+
root.style.setProperty(EINBLICK_ACCENT_COLOR_VAR, this.accentColor);
|
|
573
|
+
}
|
|
574
|
+
restoreAccentColor() {
|
|
575
|
+
if (typeof document === 'undefined' ||
|
|
576
|
+
this.originalRootAccentColor === undefined) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const root = document.documentElement;
|
|
580
|
+
if (this.originalRootAccentColor) {
|
|
581
|
+
root.style.setProperty(EINBLICK_ACCENT_COLOR_VAR, this.originalRootAccentColor);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
root.style.removeProperty(EINBLICK_ACCENT_COLOR_VAR);
|
|
585
|
+
}
|
|
586
|
+
this.originalRootAccentColor = undefined;
|
|
587
|
+
}
|
|
478
588
|
start() {
|
|
479
589
|
if (this.started ||
|
|
480
590
|
typeof window === 'undefined' ||
|
|
@@ -482,6 +592,7 @@ class EinblickEditRuntime {
|
|
|
482
592
|
return;
|
|
483
593
|
}
|
|
484
594
|
this.started = true;
|
|
595
|
+
this.applyAccentColor();
|
|
485
596
|
injectRuntimeStyles();
|
|
486
597
|
this.ensureHoverButton();
|
|
487
598
|
if (this.chrome === 'badge') {
|
|
@@ -493,6 +604,7 @@ class EinblickEditRuntime {
|
|
|
493
604
|
window.addEventListener('message', this.handleMessage);
|
|
494
605
|
window.addEventListener('pointerdown', this.handleGlobalPointerDown, true);
|
|
495
606
|
window.addEventListener('pointermove', this.handlePointerMove, true);
|
|
607
|
+
window.addEventListener('click', this.handleCollectionCreateButtonClick, true);
|
|
496
608
|
window.addEventListener('scroll', this.handleViewportChange, true);
|
|
497
609
|
window.addEventListener('resize', this.handleViewportChange);
|
|
498
610
|
window.addEventListener('blur', this.handleWindowBlur);
|
|
@@ -508,12 +620,14 @@ class EinblickEditRuntime {
|
|
|
508
620
|
this.closeInlineEditor();
|
|
509
621
|
}
|
|
510
622
|
this.updateBottomBarResources();
|
|
623
|
+
this.updateCollectionCreateButtons();
|
|
511
624
|
});
|
|
512
625
|
this.mutationObserver.observe(document.body, {
|
|
513
626
|
childList: true,
|
|
514
627
|
subtree: true,
|
|
515
628
|
});
|
|
516
629
|
this.reloadBridge();
|
|
630
|
+
this.updateCollectionCreateButtons();
|
|
517
631
|
}
|
|
518
632
|
destroy() {
|
|
519
633
|
if (this.destroyed) {
|
|
@@ -524,6 +638,7 @@ class EinblickEditRuntime {
|
|
|
524
638
|
window.removeEventListener('message', this.handleMessage);
|
|
525
639
|
window.removeEventListener('pointerdown', this.handleGlobalPointerDown, true);
|
|
526
640
|
window.removeEventListener('pointermove', this.handlePointerMove, true);
|
|
641
|
+
window.removeEventListener('click', this.handleCollectionCreateButtonClick, true);
|
|
527
642
|
window.removeEventListener('scroll', this.handleViewportChange, true);
|
|
528
643
|
window.removeEventListener('resize', this.handleViewportChange);
|
|
529
644
|
window.removeEventListener('blur', this.handleWindowBlur);
|
|
@@ -543,8 +658,6 @@ class EinblickEditRuntime {
|
|
|
543
658
|
this.hoverButtonContainer = null;
|
|
544
659
|
this.hoverButton?.remove();
|
|
545
660
|
this.hoverButton = null;
|
|
546
|
-
this.hoverCreateButton?.remove();
|
|
547
|
-
this.hoverCreateButton = null;
|
|
548
661
|
this.clearQuickFieldOverlays();
|
|
549
662
|
this.brandBadge?.remove();
|
|
550
663
|
this.brandBadge = null;
|
|
@@ -567,6 +680,7 @@ class EinblickEditRuntime {
|
|
|
567
680
|
this.closeInlineEditor();
|
|
568
681
|
this.removeNavigatorPanel(false);
|
|
569
682
|
this.closeDrawer();
|
|
683
|
+
this.restoreAccentColor();
|
|
570
684
|
if (this.pendingLogin) {
|
|
571
685
|
if (this.pendingLogin.closePollId !== null) {
|
|
572
686
|
window.clearInterval(this.pendingLogin.closePollId);
|
|
@@ -597,9 +711,6 @@ class EinblickEditRuntime {
|
|
|
597
711
|
if (this.hoverButton) {
|
|
598
712
|
this.updateHoverButtonLabel();
|
|
599
713
|
}
|
|
600
|
-
if (this.hoverCreateButton) {
|
|
601
|
-
this.hoverCreateButton.textContent = this.messages.actions.addRecord;
|
|
602
|
-
}
|
|
603
714
|
if (this.brandBadge) {
|
|
604
715
|
this.brandBadge.setAttribute('aria-label', this.messages.brand.quickActionsLabel);
|
|
605
716
|
this.brandBadge.title = this.messages.brand.quickActionsLabel;
|
|
@@ -616,12 +727,19 @@ class EinblickEditRuntime {
|
|
|
616
727
|
}
|
|
617
728
|
this.updateBrandPopover();
|
|
618
729
|
this.updateBottomBar();
|
|
730
|
+
this.updateCollectionCreateButtons();
|
|
619
731
|
this.updateHoverChrome();
|
|
620
732
|
}
|
|
621
733
|
async login(options) {
|
|
622
734
|
if (typeof window === 'undefined') {
|
|
623
735
|
return false;
|
|
624
736
|
}
|
|
737
|
+
if (!this.brokerId) {
|
|
738
|
+
const message = this.messages.errors.bridgeNotConnected;
|
|
739
|
+
this.callbacks.onError?.(message);
|
|
740
|
+
this.pingBridge();
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
625
743
|
const returnTo = options?.returnTo ?? window.location.href;
|
|
626
744
|
const loginNonce = createRandomId();
|
|
627
745
|
const loginUrl = this.buildBridgeUrl({
|
|
@@ -743,22 +861,31 @@ class EinblickEditRuntime {
|
|
|
743
861
|
!this.shouldShowEditButton(this.activeElement, binding)) {
|
|
744
862
|
return;
|
|
745
863
|
}
|
|
864
|
+
if (binding.fieldKey && isMultiMediaBinding(binding)) {
|
|
865
|
+
this.openDrawer(this.activeElement, binding);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
746
868
|
if (binding.fieldKey && isMediaEditableBinding(binding)) {
|
|
747
869
|
this.openMediaPicker(this.activeElement, binding, this.hoverButton);
|
|
748
870
|
return;
|
|
749
871
|
}
|
|
750
872
|
this.openEditor(binding, this.activeElement);
|
|
751
873
|
};
|
|
752
|
-
|
|
874
|
+
handleCollectionCreateButtonClick = (event) => {
|
|
875
|
+
const button = this.findCollectionCreateButton(event.target);
|
|
876
|
+
if (!button) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
753
879
|
stopEvent(event);
|
|
754
|
-
|
|
880
|
+
const collection = this.findCollectionForCreateButton(button);
|
|
881
|
+
if (!collection) {
|
|
755
882
|
return;
|
|
756
883
|
}
|
|
757
|
-
const binding = readBindingFromElement(
|
|
758
|
-
if (!binding || !this.shouldShowCreateButton(
|
|
884
|
+
const binding = readBindingFromElement(collection);
|
|
885
|
+
if (!binding || !this.shouldShowCreateButton(collection, binding)) {
|
|
759
886
|
return;
|
|
760
887
|
}
|
|
761
|
-
this.openDrawer(
|
|
888
|
+
this.openDrawer(collection, binding, 'create');
|
|
762
889
|
};
|
|
763
890
|
handleGlobalPointerDown = (event) => {
|
|
764
891
|
const target = event.target;
|
|
@@ -806,14 +933,24 @@ class EinblickEditRuntime {
|
|
|
806
933
|
return;
|
|
807
934
|
}
|
|
808
935
|
if (data.source === EINBLICK_BRIDGE_SOURCE) {
|
|
936
|
+
if (event.source !== this.bridgeFrame?.contentWindow) {
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
809
939
|
this.handleBridgeMessage(data);
|
|
810
940
|
return;
|
|
811
941
|
}
|
|
812
942
|
if (data.source === EINBLICK_AUTH_SOURCE) {
|
|
943
|
+
if (event.source !== this.pendingLogin?.popup) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
813
946
|
this.handleAuthMessage(data);
|
|
814
947
|
return;
|
|
815
948
|
}
|
|
816
949
|
if (data.source === EINBLICK_EDITOR_SOURCE) {
|
|
950
|
+
if (event.source !== this.editorFrame?.contentWindow &&
|
|
951
|
+
event.source !== this.navigatorFrame?.contentWindow) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
817
954
|
this.handleEditorMessage(data);
|
|
818
955
|
}
|
|
819
956
|
};
|
|
@@ -823,7 +960,9 @@ class EinblickEditRuntime {
|
|
|
823
960
|
}
|
|
824
961
|
if (message.type === 'bridge-ready') {
|
|
825
962
|
this.clearBridgePing();
|
|
963
|
+
this.brokerId = message.brokerId ?? this.brokerId;
|
|
826
964
|
if (message.authenticated) {
|
|
965
|
+
this.setSession({ active: true, expiresAt: message.expiresAt });
|
|
827
966
|
this.setState({
|
|
828
967
|
enabled: true,
|
|
829
968
|
active: true,
|
|
@@ -851,6 +990,26 @@ class EinblickEditRuntime {
|
|
|
851
990
|
}
|
|
852
991
|
return;
|
|
853
992
|
}
|
|
993
|
+
if (message.type === 'broker-proof-result') {
|
|
994
|
+
const pending = this.pendingLogin;
|
|
995
|
+
if (!pending ||
|
|
996
|
+
message.requestId !== pending.nonce ||
|
|
997
|
+
message.brokerId !== this.brokerId) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
try {
|
|
1001
|
+
pending.popup?.postMessage({
|
|
1002
|
+
source: EINBLICK_AUTH_SOURCE,
|
|
1003
|
+
type: 'broker-proof-result',
|
|
1004
|
+
nonce: pending.nonce,
|
|
1005
|
+
requestId: message.requestId,
|
|
1006
|
+
brokerId: message.brokerId,
|
|
1007
|
+
ciphertext: message.ciphertext,
|
|
1008
|
+
}, this.appOrigin);
|
|
1009
|
+
}
|
|
1010
|
+
catch { }
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
854
1013
|
if (message.type === 'logout-result') {
|
|
855
1014
|
const pending = this.pendingLogout;
|
|
856
1015
|
if (!pending || pending.requestId !== message.requestId) {
|
|
@@ -898,28 +1057,43 @@ class EinblickEditRuntime {
|
|
|
898
1057
|
if (!this.pendingLogin || message.nonce !== this.pendingLogin.nonce) {
|
|
899
1058
|
return;
|
|
900
1059
|
}
|
|
1060
|
+
if (message.type === 'broker-proof-request') {
|
|
1061
|
+
if (message.requestId !== this.pendingLogin.nonce ||
|
|
1062
|
+
message.brokerId !== this.brokerId ||
|
|
1063
|
+
!this.bridgeFrame?.contentWindow) {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
try {
|
|
1067
|
+
this.bridgeFrame.contentWindow.postMessage({
|
|
1068
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
1069
|
+
type: 'broker-proof-request',
|
|
1070
|
+
nonce: this.bridgeNonce,
|
|
1071
|
+
requestId: message.requestId,
|
|
1072
|
+
brokerId: message.brokerId,
|
|
1073
|
+
publicKey: message.publicKey,
|
|
1074
|
+
}, this.appOrigin);
|
|
1075
|
+
}
|
|
1076
|
+
catch { }
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
901
1079
|
if (this.pendingLogin.closePollId !== null) {
|
|
902
1080
|
window.clearInterval(this.pendingLogin.closePollId);
|
|
903
1081
|
}
|
|
904
1082
|
const pending = this.pendingLogin;
|
|
905
1083
|
this.pendingLogin = null;
|
|
906
1084
|
if (message.ok) {
|
|
907
|
-
if (!message.
|
|
1085
|
+
if (!message.brokerId || message.brokerId !== this.brokerId) {
|
|
908
1086
|
const errorMessage = this.messages.errors.signInDidNotReturnSession;
|
|
909
1087
|
this.setState({ ...this.state, errorMessage, status: 'error' });
|
|
910
1088
|
this.callbacks.onError?.(errorMessage);
|
|
911
1089
|
pending.resolve(false);
|
|
912
1090
|
return;
|
|
913
1091
|
}
|
|
914
|
-
this.setSession({
|
|
915
|
-
sessionToken: message.sessionToken,
|
|
916
|
-
expiresAt: message.expiresAt,
|
|
917
|
-
});
|
|
918
1092
|
try {
|
|
919
1093
|
pending.popup?.close();
|
|
920
1094
|
}
|
|
921
1095
|
catch { }
|
|
922
|
-
this.
|
|
1096
|
+
this.pingBridge();
|
|
923
1097
|
pending.resolve(true);
|
|
924
1098
|
return;
|
|
925
1099
|
}
|
|
@@ -1020,30 +1194,20 @@ class EinblickEditRuntime {
|
|
|
1020
1194
|
}
|
|
1021
1195
|
}
|
|
1022
1196
|
setSession(session) {
|
|
1023
|
-
const
|
|
1197
|
+
const wasActive = this.session !== null;
|
|
1024
1198
|
this.session = session && !isEditSessionExpired(session) ? session : null;
|
|
1025
|
-
|
|
1026
|
-
if (previousSessionToken !== nextSessionToken) {
|
|
1199
|
+
if (wasActive !== (this.session !== null)) {
|
|
1027
1200
|
this.removeNavigatorPanel(false);
|
|
1028
1201
|
}
|
|
1029
1202
|
this.callbacks.onSessionChange(this.session);
|
|
1030
1203
|
}
|
|
1031
|
-
getActiveSessionToken() {
|
|
1032
|
-
if (!this.session) {
|
|
1033
|
-
return null;
|
|
1034
|
-
}
|
|
1035
|
-
if (isEditSessionExpired(this.session)) {
|
|
1036
|
-
this.setSession(null);
|
|
1037
|
-
return null;
|
|
1038
|
-
}
|
|
1039
|
-
return this.session.sessionToken;
|
|
1040
|
-
}
|
|
1041
1204
|
setState(nextState) {
|
|
1042
1205
|
this.state = nextState;
|
|
1043
1206
|
this.callbacks.onStateChange(nextState);
|
|
1044
1207
|
this.updateBrandBadge();
|
|
1045
1208
|
this.updateBrandPopover();
|
|
1046
1209
|
this.updateBottomBar();
|
|
1210
|
+
this.updateCollectionCreateButtons();
|
|
1047
1211
|
if (!nextState.isAuthenticated) {
|
|
1048
1212
|
this.setActiveElement(null);
|
|
1049
1213
|
this.removeNavigatorPanel();
|
|
@@ -1058,26 +1222,18 @@ class EinblickEditRuntime {
|
|
|
1058
1222
|
container.hidden = true;
|
|
1059
1223
|
const editButton = document.createElement('button');
|
|
1060
1224
|
editButton.type = 'button';
|
|
1061
|
-
editButton
|
|
1225
|
+
setOverlayButtonContent(editButton, this.messages.actions.editElement, {
|
|
1226
|
+
databaseIcon: true,
|
|
1227
|
+
});
|
|
1062
1228
|
editButton.setAttribute('data-einblick-edit-button', 'true');
|
|
1063
1229
|
editButton.addEventListener('pointerdown', (event) => {
|
|
1064
1230
|
event.stopPropagation();
|
|
1065
1231
|
});
|
|
1066
1232
|
editButton.addEventListener('click', this.handleHoverButtonClick);
|
|
1067
|
-
|
|
1068
|
-
createButton.type = 'button';
|
|
1069
|
-
createButton.textContent = this.messages.actions.addRecord;
|
|
1070
|
-
createButton.hidden = true;
|
|
1071
|
-
createButton.setAttribute('data-einblick-create-button', 'true');
|
|
1072
|
-
createButton.addEventListener('pointerdown', (event) => {
|
|
1073
|
-
event.stopPropagation();
|
|
1074
|
-
});
|
|
1075
|
-
createButton.addEventListener('click', this.handleCreateButtonClick);
|
|
1076
|
-
container.append(editButton, createButton);
|
|
1233
|
+
container.append(editButton);
|
|
1077
1234
|
document.body.append(container);
|
|
1078
1235
|
this.hoverButtonContainer = container;
|
|
1079
1236
|
this.hoverButton = editButton;
|
|
1080
|
-
this.hoverCreateButton = createButton;
|
|
1081
1237
|
}
|
|
1082
1238
|
ensureBrandBadge() {
|
|
1083
1239
|
if ((this.brandBadge && this.brandPopover) ||
|
|
@@ -1254,7 +1410,7 @@ class EinblickEditRuntime {
|
|
|
1254
1410
|
border: 0;
|
|
1255
1411
|
border-radius: 0.35rem;
|
|
1256
1412
|
background: #ffffff;
|
|
1257
|
-
color:
|
|
1413
|
+
color: ${EINBLICK_ACCENT_COLOR};
|
|
1258
1414
|
padding: 0 0.7rem;
|
|
1259
1415
|
font: 700 0.78rem/1 system-ui, sans-serif;
|
|
1260
1416
|
letter-spacing: 0;
|
|
@@ -1294,7 +1450,6 @@ class EinblickEditRuntime {
|
|
|
1294
1450
|
border-radius: 0.75rem;
|
|
1295
1451
|
background: rgb(255, 255, 255);
|
|
1296
1452
|
color: rgb(15, 23, 42);
|
|
1297
|
-
box-shadow: 0 14px 32px rgba(15, 23, 42, 0.16);
|
|
1298
1453
|
overflow: hidden;
|
|
1299
1454
|
}
|
|
1300
1455
|
|
|
@@ -1634,10 +1789,15 @@ class EinblickEditRuntime {
|
|
|
1634
1789
|
}
|
|
1635
1790
|
}
|
|
1636
1791
|
async logoutFromEinblick() {
|
|
1792
|
+
await this.endEditSession(true);
|
|
1793
|
+
}
|
|
1794
|
+
async deactivateEditSession() {
|
|
1795
|
+
await this.endEditSession(false);
|
|
1796
|
+
}
|
|
1797
|
+
async endEditSession(signOut) {
|
|
1637
1798
|
if (typeof window === 'undefined') {
|
|
1638
1799
|
return;
|
|
1639
1800
|
}
|
|
1640
|
-
const sessionToken = this.getActiveSessionToken();
|
|
1641
1801
|
this.setSession(null);
|
|
1642
1802
|
this.setState({
|
|
1643
1803
|
enabled: true,
|
|
@@ -1647,13 +1807,13 @@ class EinblickEditRuntime {
|
|
|
1647
1807
|
siteName: this.state.siteName,
|
|
1648
1808
|
errorMessage: undefined,
|
|
1649
1809
|
});
|
|
1650
|
-
const loggedOutViaBridge = await this.requestBridgeLogout();
|
|
1810
|
+
const loggedOutViaBridge = await this.requestBridgeLogout(signOut);
|
|
1651
1811
|
if (!loggedOutViaBridge) {
|
|
1652
|
-
await this.logoutViaPopup(
|
|
1812
|
+
await this.logoutViaPopup(signOut);
|
|
1653
1813
|
}
|
|
1654
1814
|
this.reloadBridge();
|
|
1655
1815
|
}
|
|
1656
|
-
requestBridgeLogout() {
|
|
1816
|
+
requestBridgeLogout(signOut) {
|
|
1657
1817
|
if (typeof window === 'undefined' || this.pendingLogout) {
|
|
1658
1818
|
return Promise.resolve(false);
|
|
1659
1819
|
}
|
|
@@ -1677,6 +1837,7 @@ class EinblickEditRuntime {
|
|
|
1677
1837
|
type: 'logout',
|
|
1678
1838
|
nonce: this.bridgeNonce,
|
|
1679
1839
|
requestId,
|
|
1840
|
+
signOut,
|
|
1680
1841
|
}, this.appOrigin);
|
|
1681
1842
|
}
|
|
1682
1843
|
catch {
|
|
@@ -1688,12 +1849,12 @@ class EinblickEditRuntime {
|
|
|
1688
1849
|
}
|
|
1689
1850
|
});
|
|
1690
1851
|
}
|
|
1691
|
-
async logoutViaPopup(
|
|
1852
|
+
async logoutViaPopup(signOut) {
|
|
1692
1853
|
const logoutUrl = this.buildBridgeUrl({
|
|
1693
1854
|
mode: 'logout',
|
|
1694
1855
|
nonce: createRandomId(),
|
|
1695
1856
|
returnTo: window.location.href,
|
|
1696
|
-
|
|
1857
|
+
signOut,
|
|
1697
1858
|
});
|
|
1698
1859
|
let popup = null;
|
|
1699
1860
|
try {
|
|
@@ -1736,9 +1897,6 @@ class EinblickEditRuntime {
|
|
|
1736
1897
|
if (this.hoverButton) {
|
|
1737
1898
|
this.hoverButton.hidden = true;
|
|
1738
1899
|
}
|
|
1739
|
-
if (this.hoverCreateButton) {
|
|
1740
|
-
this.hoverCreateButton.hidden = true;
|
|
1741
|
-
}
|
|
1742
1900
|
return;
|
|
1743
1901
|
}
|
|
1744
1902
|
element.dataset.einblickHoverActive = 'true';
|
|
@@ -1774,6 +1932,10 @@ class EinblickEditRuntime {
|
|
|
1774
1932
|
}
|
|
1775
1933
|
this.updateHoverButtonLabel();
|
|
1776
1934
|
this.updateHoverButtonVisibility(this.activeElement);
|
|
1935
|
+
if (this.hoverButtonContainer?.hidden) {
|
|
1936
|
+
this.updateQuickFieldOverlayPositions();
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1777
1939
|
this.positionHoverControls(rect);
|
|
1778
1940
|
this.updateQuickFieldOverlayPositions();
|
|
1779
1941
|
}
|
|
@@ -1822,10 +1984,9 @@ class EinblickEditRuntime {
|
|
|
1822
1984
|
const button = document.createElement('button');
|
|
1823
1985
|
button.type = 'button';
|
|
1824
1986
|
button.setAttribute('data-einblick-field-button', isMediaBinding ? 'media' : 'text');
|
|
1825
|
-
button
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
: this.messages.actions.editText;
|
|
1987
|
+
setOverlayButtonContent(button, isMediaBinding
|
|
1988
|
+
? getMediaActionLabel(binding, this.messages)
|
|
1989
|
+
: this.messages.actions.editText);
|
|
1829
1990
|
button.addEventListener('pointerdown', (event) => {
|
|
1830
1991
|
event.stopPropagation();
|
|
1831
1992
|
});
|
|
@@ -1867,8 +2028,37 @@ class EinblickEditRuntime {
|
|
|
1867
2028
|
const height = overlay.button.offsetHeight || 26;
|
|
1868
2029
|
const scrollX = window.scrollX || document.documentElement.scrollLeft;
|
|
1869
2030
|
const scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
1870
|
-
|
|
1871
|
-
|
|
2031
|
+
let left = clamp(rect.right + scrollX - width, scrollX, Math.max(scrollX, scrollX + window.innerWidth - width));
|
|
2032
|
+
let top = clamp(rect.top + scrollY, scrollY, Math.max(scrollY, scrollY + window.innerHeight - height));
|
|
2033
|
+
const hoverControlsRect = this.hoverButtonContainer && !this.hoverButtonContainer.hidden
|
|
2034
|
+
? this.hoverButtonContainer.getBoundingClientRect()
|
|
2035
|
+
: null;
|
|
2036
|
+
if (hoverControlsRect) {
|
|
2037
|
+
const candidateRect = {
|
|
2038
|
+
left: left - scrollX,
|
|
2039
|
+
top: top - scrollY,
|
|
2040
|
+
right: left - scrollX + width,
|
|
2041
|
+
bottom: top - scrollY + height,
|
|
2042
|
+
};
|
|
2043
|
+
if (rectsOverlap(candidateRect, hoverControlsRect, 6)) {
|
|
2044
|
+
const minTop = scrollY;
|
|
2045
|
+
const maxTop = Math.max(scrollY, scrollY + window.innerHeight - height);
|
|
2046
|
+
const belowTop = hoverControlsRect.bottom + scrollY + 6;
|
|
2047
|
+
const aboveTop = hoverControlsRect.top + scrollY - height - 6;
|
|
2048
|
+
if (belowTop <= maxTop) {
|
|
2049
|
+
top = clamp(belowTop, minTop, maxTop);
|
|
2050
|
+
}
|
|
2051
|
+
else if (aboveTop >= minTop) {
|
|
2052
|
+
top = clamp(aboveTop, minTop, maxTop);
|
|
2053
|
+
}
|
|
2054
|
+
else {
|
|
2055
|
+
const maxLeft = Math.max(scrollX, scrollX + window.innerWidth - width);
|
|
2056
|
+
const leftOfControls = hoverControlsRect.left + scrollX - width - 6;
|
|
2057
|
+
const rightOfControls = hoverControlsRect.right + scrollX + 6;
|
|
2058
|
+
left = clamp(leftOfControls >= scrollX ? leftOfControls : rightOfControls, scrollX, maxLeft);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
1872
2062
|
overlay.button.style.left = `${Math.round(left)}px`;
|
|
1873
2063
|
overlay.button.style.top = `${Math.round(top)}px`;
|
|
1874
2064
|
}
|
|
@@ -1879,14 +2069,19 @@ class EinblickEditRuntime {
|
|
|
1879
2069
|
}
|
|
1880
2070
|
const binding = readBindingFromElement(this.activeElement);
|
|
1881
2071
|
if (!binding?.fieldKey) {
|
|
1882
|
-
this.hoverButton
|
|
2072
|
+
setOverlayButtonContent(this.hoverButton, this.messages.actions.editElement, { databaseIcon: true });
|
|
1883
2073
|
return;
|
|
1884
2074
|
}
|
|
1885
|
-
|
|
2075
|
+
const opensDrawer = isMultiMediaBinding(binding) ||
|
|
2076
|
+
(!isMediaEditableBinding(binding) && !shouldUseInlineEditor(binding));
|
|
2077
|
+
const label = isMediaEditableBinding(binding)
|
|
1886
2078
|
? getMediaActionLabel(binding, this.messages)
|
|
1887
2079
|
: shouldUseInlineEditor(binding)
|
|
1888
2080
|
? this.messages.actions.editText
|
|
1889
|
-
: this.messages.actions.
|
|
2081
|
+
: this.messages.actions.editElement;
|
|
2082
|
+
setOverlayButtonContent(this.hoverButton, label, {
|
|
2083
|
+
databaseIcon: opensDrawer,
|
|
2084
|
+
});
|
|
1890
2085
|
}
|
|
1891
2086
|
reloadBridge() {
|
|
1892
2087
|
this.clearBridgePing();
|
|
@@ -1907,23 +2102,22 @@ class EinblickEditRuntime {
|
|
|
1907
2102
|
frame.src = this.buildBridgeUrl({ mode: 'bridge', nonce: this.bridgeNonce });
|
|
1908
2103
|
this.bridgeFrame = frame;
|
|
1909
2104
|
document.body.append(frame);
|
|
1910
|
-
const sendPing = () => {
|
|
1911
|
-
if (!this.bridgeFrame?.contentWindow) {
|
|
1912
|
-
return;
|
|
1913
|
-
}
|
|
1914
|
-
try {
|
|
1915
|
-
this.bridgeFrame.contentWindow.postMessage({
|
|
1916
|
-
source: EINBLICK_PARENT_SOURCE,
|
|
1917
|
-
type: 'bridge-ping',
|
|
1918
|
-
nonce: this.bridgeNonce,
|
|
1919
|
-
}, this.appOrigin);
|
|
1920
|
-
}
|
|
1921
|
-
catch { }
|
|
1922
|
-
};
|
|
1923
2105
|
frame.addEventListener('load', () => {
|
|
1924
|
-
|
|
2106
|
+
this.pingBridge();
|
|
1925
2107
|
});
|
|
1926
|
-
this.bridgePingInterval = window.setInterval(
|
|
2108
|
+
this.bridgePingInterval = window.setInterval(() => this.pingBridge(), 1500);
|
|
2109
|
+
}
|
|
2110
|
+
pingBridge() {
|
|
2111
|
+
if (!this.bridgeFrame?.contentWindow)
|
|
2112
|
+
return;
|
|
2113
|
+
try {
|
|
2114
|
+
this.bridgeFrame.contentWindow.postMessage({
|
|
2115
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
2116
|
+
type: 'bridge-ping',
|
|
2117
|
+
nonce: this.bridgeNonce,
|
|
2118
|
+
}, this.appOrigin);
|
|
2119
|
+
}
|
|
2120
|
+
catch { }
|
|
1927
2121
|
}
|
|
1928
2122
|
clearBridgePing() {
|
|
1929
2123
|
if (this.bridgePingInterval !== null) {
|
|
@@ -1936,28 +2130,33 @@ class EinblickEditRuntime {
|
|
|
1936
2130
|
url.searchParams.set('siteKey', this.siteKey);
|
|
1937
2131
|
url.searchParams.set('origin', window.location.origin);
|
|
1938
2132
|
url.searchParams.set('nonce', args.nonce);
|
|
2133
|
+
url.searchParams.set('protocol', '2');
|
|
2134
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
1939
2135
|
if (args.mode !== 'bridge') {
|
|
1940
2136
|
url.searchParams.set('mode', args.mode);
|
|
1941
2137
|
}
|
|
1942
|
-
const
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
url.searchParams.set('sessionToken', sessionToken);
|
|
2138
|
+
const brokerId = args.brokerId ?? (args.mode === 'login' ? this.brokerId : null);
|
|
2139
|
+
if (brokerId) {
|
|
2140
|
+
url.searchParams.set('brokerId', brokerId);
|
|
1946
2141
|
}
|
|
1947
2142
|
if (args.returnTo) {
|
|
1948
2143
|
url.searchParams.set('returnTo', args.returnTo);
|
|
1949
2144
|
}
|
|
2145
|
+
if (args.signOut === false) {
|
|
2146
|
+
url.searchParams.set('signOut', '0');
|
|
2147
|
+
}
|
|
1950
2148
|
return url.toString();
|
|
1951
2149
|
}
|
|
1952
2150
|
buildEditorUrl(binding, nonce, intent = 'edit') {
|
|
1953
|
-
|
|
1954
|
-
if (!sessionToken) {
|
|
2151
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
1955
2152
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
1956
2153
|
}
|
|
1957
2154
|
const url = new URL('/sdk/editor', this.appOrigin);
|
|
1958
2155
|
url.searchParams.set('origin', window.location.origin);
|
|
1959
2156
|
url.searchParams.set('nonce', nonce);
|
|
1960
|
-
url.searchParams.set('
|
|
2157
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2158
|
+
url.searchParams.set('protocol', '2');
|
|
2159
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
1961
2160
|
url.searchParams.set('returnTo', window.location.href);
|
|
1962
2161
|
url.searchParams.set('sourceType', binding.sourceType ?? 'cms');
|
|
1963
2162
|
url.searchParams.set('resourceSlug', binding.resourceSlug);
|
|
@@ -1976,25 +2175,27 @@ class EinblickEditRuntime {
|
|
|
1976
2175
|
return url.toString();
|
|
1977
2176
|
}
|
|
1978
2177
|
buildNavigatorUrl(nonce) {
|
|
1979
|
-
|
|
1980
|
-
if (!sessionToken) {
|
|
2178
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
1981
2179
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
1982
2180
|
}
|
|
1983
2181
|
const url = new URL('/sdk/navigator', this.appOrigin);
|
|
1984
2182
|
url.searchParams.set('origin', window.location.origin);
|
|
1985
2183
|
url.searchParams.set('nonce', nonce);
|
|
1986
|
-
url.searchParams.set('
|
|
2184
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2185
|
+
url.searchParams.set('protocol', '2');
|
|
2186
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
1987
2187
|
return url.toString();
|
|
1988
2188
|
}
|
|
1989
2189
|
buildCollectionEditorUrl(args) {
|
|
1990
|
-
|
|
1991
|
-
if (!sessionToken) {
|
|
2190
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
1992
2191
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
1993
2192
|
}
|
|
1994
2193
|
const url = new URL('/sdk/editor', this.appOrigin);
|
|
1995
2194
|
url.searchParams.set('origin', window.location.origin);
|
|
1996
2195
|
url.searchParams.set('nonce', args.nonce);
|
|
1997
|
-
url.searchParams.set('
|
|
2196
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2197
|
+
url.searchParams.set('protocol', '2');
|
|
2198
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
1998
2199
|
url.searchParams.set('returnTo', window.location.href);
|
|
1999
2200
|
url.searchParams.set('sourceType', args.sourceType ?? 'cms');
|
|
2000
2201
|
url.searchParams.set('collectionId', args.collectionId);
|
|
@@ -2008,16 +2209,51 @@ class EinblickEditRuntime {
|
|
|
2008
2209
|
return url.toString();
|
|
2009
2210
|
}
|
|
2010
2211
|
updateHoverButtonVisibility(element) {
|
|
2011
|
-
if (!this.hoverButton
|
|
2212
|
+
if (!this.hoverButton) {
|
|
2012
2213
|
return;
|
|
2013
2214
|
}
|
|
2014
2215
|
const binding = element ? readBindingFromElement(element) : null;
|
|
2015
|
-
const canCreate = this.shouldShowCreateButton(element, binding);
|
|
2016
2216
|
const canEdit = this.shouldShowEditButton(element, binding);
|
|
2017
2217
|
this.hoverButton.hidden = !canEdit;
|
|
2018
|
-
this.hoverCreateButton.hidden = !canCreate;
|
|
2019
2218
|
if (this.hoverButtonContainer) {
|
|
2020
|
-
this.hoverButtonContainer.hidden = !canEdit
|
|
2219
|
+
this.hoverButtonContainer.hidden = !canEdit;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
findCollectionCreateButton(target) {
|
|
2223
|
+
const element = target instanceof Element
|
|
2224
|
+
? target
|
|
2225
|
+
: target instanceof Node
|
|
2226
|
+
? target.parentElement
|
|
2227
|
+
: null;
|
|
2228
|
+
if (!element) {
|
|
2229
|
+
return null;
|
|
2230
|
+
}
|
|
2231
|
+
return element.closest('[data-einblick-collection-create-button="true"]');
|
|
2232
|
+
}
|
|
2233
|
+
findCollectionForCreateButton(button) {
|
|
2234
|
+
return button.closest('[data-einblick-editable="true"][data-einblick-kind="collection"]');
|
|
2235
|
+
}
|
|
2236
|
+
updateCollectionCreateButtons() {
|
|
2237
|
+
if (typeof document === 'undefined') {
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
const buttons = Array.from(document.querySelectorAll('[data-einblick-collection-create-button="true"]'));
|
|
2241
|
+
for (const button of buttons) {
|
|
2242
|
+
const label = button.dataset.einblickCollectionCreateLabel?.trim() ||
|
|
2243
|
+
this.messages.actions.addRecord;
|
|
2244
|
+
setOverlayButtonContent(button, label, { databaseIcon: true });
|
|
2245
|
+
button.type = 'button';
|
|
2246
|
+
const collection = this.findCollectionForCreateButton(button);
|
|
2247
|
+
const binding = collection ? readBindingFromElement(collection) : null;
|
|
2248
|
+
const isVisible = !!collection &&
|
|
2249
|
+
!!binding &&
|
|
2250
|
+
this.shouldShowCreateButton(collection, binding);
|
|
2251
|
+
button.hidden = !isVisible;
|
|
2252
|
+
button.disabled = !isVisible;
|
|
2253
|
+
const wrapper = button.closest('[data-einblick-collection-create-wrapper="true"]');
|
|
2254
|
+
if (wrapper) {
|
|
2255
|
+
wrapper.hidden = !isVisible;
|
|
2256
|
+
}
|
|
2021
2257
|
}
|
|
2022
2258
|
}
|
|
2023
2259
|
shouldShowEditButton(element, binding) {
|
|
@@ -2033,7 +2269,10 @@ class EinblickEditRuntime {
|
|
|
2033
2269
|
if (binding.fieldKey) {
|
|
2034
2270
|
return false;
|
|
2035
2271
|
}
|
|
2036
|
-
|
|
2272
|
+
if (element.dataset.einblickKind !== 'collection') {
|
|
2273
|
+
return false;
|
|
2274
|
+
}
|
|
2275
|
+
return true;
|
|
2037
2276
|
}
|
|
2038
2277
|
findEditableTarget(target) {
|
|
2039
2278
|
if (!(target instanceof Element)) {
|
|
@@ -2102,7 +2341,8 @@ class EinblickEditRuntime {
|
|
|
2102
2341
|
!!this.brandBadge?.contains(target) ||
|
|
2103
2342
|
!!this.brandPopover?.contains(target) ||
|
|
2104
2343
|
!!this.bottomBarHost?.contains(target) ||
|
|
2105
|
-
!!this.bottomBarMoreMenu?.contains(target)
|
|
2344
|
+
!!this.bottomBarMoreMenu?.contains(target) ||
|
|
2345
|
+
!!this.findCollectionCreateButton(target));
|
|
2106
2346
|
}
|
|
2107
2347
|
findElementForBinding(binding) {
|
|
2108
2348
|
const selector = [
|
|
@@ -2354,18 +2594,21 @@ class EinblickEditRuntime {
|
|
|
2354
2594
|
this.callbacks.onError?.(this.messages.errors.fieldBindingRequired);
|
|
2355
2595
|
return;
|
|
2356
2596
|
}
|
|
2597
|
+
if (isMultiMediaBinding(binding)) {
|
|
2598
|
+
this.openDrawer(target, binding);
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2357
2601
|
const input = document.createElement('input');
|
|
2358
2602
|
input.type = 'file';
|
|
2359
2603
|
input.accept = getMediaAcceptValue(binding);
|
|
2360
2604
|
input.style.position = 'fixed';
|
|
2361
2605
|
input.style.left = '-9999px';
|
|
2362
2606
|
input.style.top = '0';
|
|
2363
|
-
const
|
|
2607
|
+
const buttonLabel = getMediaActionLabel(binding, this.messages);
|
|
2364
2608
|
const resetButton = () => {
|
|
2365
2609
|
if (button) {
|
|
2366
2610
|
button.disabled = false;
|
|
2367
|
-
button
|
|
2368
|
-
previousText || getMediaActionLabel(binding, this.messages);
|
|
2611
|
+
setOverlayButtonContent(button, buttonLabel);
|
|
2369
2612
|
}
|
|
2370
2613
|
};
|
|
2371
2614
|
input.addEventListener('change', () => {
|
|
@@ -2376,7 +2619,7 @@ class EinblickEditRuntime {
|
|
|
2376
2619
|
}
|
|
2377
2620
|
if (button) {
|
|
2378
2621
|
button.disabled = true;
|
|
2379
|
-
button
|
|
2622
|
+
setOverlayButtonContent(button, this.messages.actions.uploading);
|
|
2380
2623
|
}
|
|
2381
2624
|
void (async () => {
|
|
2382
2625
|
try {
|
|
@@ -2537,6 +2780,7 @@ class EinblickEditRuntime {
|
|
|
2537
2780
|
});
|
|
2538
2781
|
document.body.append(backdrop);
|
|
2539
2782
|
this.editorBackdrop = backdrop;
|
|
2783
|
+
this.editorFrame = iframe;
|
|
2540
2784
|
}
|
|
2541
2785
|
openCollectionDrawer(args) {
|
|
2542
2786
|
if (!this.state.isAuthenticated) {
|
|
@@ -2593,6 +2837,7 @@ class EinblickEditRuntime {
|
|
|
2593
2837
|
});
|
|
2594
2838
|
document.body.append(backdrop);
|
|
2595
2839
|
this.editorBackdrop = backdrop;
|
|
2840
|
+
this.editorFrame = iframe;
|
|
2596
2841
|
}
|
|
2597
2842
|
isBottomBarMenuOpen() {
|
|
2598
2843
|
return !!this.bottomBarMoreMenu && !this.bottomBarMoreMenu.hidden;
|
|
@@ -2608,6 +2853,7 @@ class EinblickEditRuntime {
|
|
|
2608
2853
|
closeDrawer() {
|
|
2609
2854
|
this.editorBackdrop?.remove();
|
|
2610
2855
|
this.editorBackdrop = null;
|
|
2856
|
+
this.editorFrame = null;
|
|
2611
2857
|
this.editorNonce = null;
|
|
2612
2858
|
this.editorTarget = null;
|
|
2613
2859
|
this.editorBinding = null;
|
|
@@ -2639,8 +2885,11 @@ export function createEinblickEditRuntime(options) {
|
|
|
2639
2885
|
start: () => runtime.start(),
|
|
2640
2886
|
destroy: () => runtime.destroy(),
|
|
2641
2887
|
login: (loginOptions) => runtime.login(loginOptions),
|
|
2888
|
+
deactivate: () => runtime.deactivateEditSession(),
|
|
2889
|
+
logout: () => runtime.logoutFromEinblick(),
|
|
2642
2890
|
openEditor: (binding, element) => runtime.openEditor(binding, element),
|
|
2643
2891
|
setLocale: (locale) => runtime.setLocale(locale),
|
|
2892
|
+
setAccentColor: (accentColor) => runtime.setAccentColor(accentColor),
|
|
2644
2893
|
};
|
|
2645
2894
|
}
|
|
2646
2895
|
//# sourceMappingURL=runtime.js.map
|