@einblick/sdk 0.7.0 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -11
- 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 +5 -17
- package/dist/next/edit-boot.d.ts.map +1 -1
- package/dist/next/edit-boot.js +5 -25
- 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.map +1 -1
- package/dist/react/markers.js +20 -17
- package/dist/react/markers.js.map +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/provider.js +11 -2
- package/dist/react/provider.js.map +1 -1
- package/dist/react/runtime.d.ts +3 -0
- package/dist/react/runtime.d.ts.map +1 -1
- package/dist/react/runtime.js +307 -95
- package/dist/react/runtime.js.map +1 -1
- package/dist/react/shared.d.ts.map +1 -1
- package/dist/react/shared.js +10 -10
- package/dist/react/shared.js.map +1 -1
- package/dist/react/types.d.ts +2 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/types.js.map +1 -1
- package/package.json +3 -6
- 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
|
@@ -7,6 +7,7 @@ const EINBLICK_ACCENT_COLOR = `var(${EINBLICK_ACCENT_COLOR_VAR}, ${DEFAULT_EINBL
|
|
|
7
7
|
const EINBLICK_ACCENT_TINT = `color-mix(in srgb, ${EINBLICK_ACCENT_COLOR} 12%, transparent)`;
|
|
8
8
|
const EINBLICK_ACCENT_HOVER_COLOR = `color-mix(in srgb, ${EINBLICK_ACCENT_COLOR} 92%, black)`;
|
|
9
9
|
const CONTROL_BAR_HEIGHT = 44;
|
|
10
|
+
const BRIDGE_CONNECTION_TIMEOUT_MS = 8000;
|
|
10
11
|
function getBrandBadgeSvg(size) {
|
|
11
12
|
return `
|
|
12
13
|
<svg viewBox="0 0 40 40" width="${size}" height="${size}" aria-hidden="true" focusable="false">
|
|
@@ -67,11 +68,15 @@ function createDatabaseIconElement(size) {
|
|
|
67
68
|
return svg;
|
|
68
69
|
}
|
|
69
70
|
function createRandomId() {
|
|
70
|
-
if (typeof crypto
|
|
71
|
-
|
|
71
|
+
if (typeof crypto === 'undefined') {
|
|
72
|
+
throw new Error('Secure browser randomness is unavailable');
|
|
73
|
+
}
|
|
74
|
+
if (typeof crypto.randomUUID === 'function') {
|
|
72
75
|
return crypto.randomUUID();
|
|
73
76
|
}
|
|
74
|
-
|
|
77
|
+
const bytes = new Uint8Array(16);
|
|
78
|
+
crypto.getRandomValues(bytes);
|
|
79
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
75
80
|
}
|
|
76
81
|
function stopEvent(event) {
|
|
77
82
|
event.preventDefault();
|
|
@@ -202,6 +207,14 @@ function injectRuntimeStyles() {
|
|
|
202
207
|
cursor: pointer;
|
|
203
208
|
}
|
|
204
209
|
|
|
210
|
+
[data-einblick-edit-controls][hidden],
|
|
211
|
+
[data-einblick-edit-button][hidden],
|
|
212
|
+
[data-einblick-collection-create-button][hidden],
|
|
213
|
+
[data-einblick-collection-create-wrapper][hidden],
|
|
214
|
+
[data-einblick-field-button][hidden] {
|
|
215
|
+
display: none !important;
|
|
216
|
+
}
|
|
217
|
+
|
|
205
218
|
[data-einblick-edit-button] svg,
|
|
206
219
|
[data-einblick-collection-create-button] svg,
|
|
207
220
|
[data-einblick-field-button] svg {
|
|
@@ -457,12 +470,17 @@ class EinblickEditRuntime {
|
|
|
457
470
|
callbacks;
|
|
458
471
|
chrome;
|
|
459
472
|
reserveBottomSpace;
|
|
473
|
+
persist;
|
|
460
474
|
locale;
|
|
461
475
|
messages;
|
|
462
476
|
accentColor;
|
|
463
477
|
originalRootAccentColor;
|
|
464
478
|
bridgeNonce = createRandomId();
|
|
465
479
|
session;
|
|
480
|
+
brokerId = null;
|
|
481
|
+
brokerReadyWaiters = new Set();
|
|
482
|
+
collectionCreateControls = new Map();
|
|
483
|
+
loginPreparing = false;
|
|
466
484
|
state = {
|
|
467
485
|
enabled: true,
|
|
468
486
|
active: true,
|
|
@@ -500,6 +518,7 @@ class EinblickEditRuntime {
|
|
|
500
518
|
currentInlineRestoreState = null;
|
|
501
519
|
inlineSaveInFlight = null;
|
|
502
520
|
editorBackdrop = null;
|
|
521
|
+
editorFrame = null;
|
|
503
522
|
editorNonce = null;
|
|
504
523
|
editorTarget = null;
|
|
505
524
|
editorBinding = null;
|
|
@@ -517,6 +536,7 @@ class EinblickEditRuntime {
|
|
|
517
536
|
this.chrome = options.chrome ?? 'bar';
|
|
518
537
|
this.reserveBottomSpace =
|
|
519
538
|
options.reserveBottomSpace ?? this.chrome === 'bar';
|
|
539
|
+
this.persist = options.persist ?? true;
|
|
520
540
|
this.locale = resolveEinblickSdkLocale(options.locale);
|
|
521
541
|
this.messages = getEinblickSdkMessages(this.locale);
|
|
522
542
|
this.accentColor = normalizeAccentColor(options.accentColor);
|
|
@@ -673,12 +693,12 @@ class EinblickEditRuntime {
|
|
|
673
693
|
this.removeNavigatorPanel(false);
|
|
674
694
|
this.closeDrawer();
|
|
675
695
|
this.restoreAccentColor();
|
|
696
|
+
for (const control of this.collectionCreateControls.values()) {
|
|
697
|
+
control.container.remove();
|
|
698
|
+
}
|
|
699
|
+
this.collectionCreateControls.clear();
|
|
676
700
|
if (this.pendingLogin) {
|
|
677
|
-
|
|
678
|
-
window.clearInterval(this.pendingLogin.closePollId);
|
|
679
|
-
}
|
|
680
|
-
this.pendingLogin.resolve(false);
|
|
681
|
-
this.pendingLogin = null;
|
|
701
|
+
this.resolvePendingLogin(this.pendingLogin.nonce, false, true);
|
|
682
702
|
}
|
|
683
703
|
for (const pending of this.pendingInlineSaves.values()) {
|
|
684
704
|
window.clearTimeout(pending.timeoutId);
|
|
@@ -690,6 +710,7 @@ class EinblickEditRuntime {
|
|
|
690
710
|
pending.reject(new Error(this.messages.errors.editingInterrupted));
|
|
691
711
|
}
|
|
692
712
|
this.pendingInlineMediaSaves.clear();
|
|
713
|
+
this.resolveBrokerReadyWaiters(null);
|
|
693
714
|
this.setState({
|
|
694
715
|
enabled: true,
|
|
695
716
|
active: false,
|
|
@@ -726,42 +747,123 @@ class EinblickEditRuntime {
|
|
|
726
747
|
if (typeof window === 'undefined') {
|
|
727
748
|
return false;
|
|
728
749
|
}
|
|
750
|
+
if (this.pendingLogin || this.loginPreparing) {
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
this.loginPreparing = true;
|
|
729
754
|
const returnTo = options?.returnTo ?? window.location.href;
|
|
730
755
|
const loginNonce = createRandomId();
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
756
|
+
const popupFeatures = 'popup=yes,width=680,height=820,resizable=yes,scrollbars=yes';
|
|
757
|
+
let popup = null;
|
|
758
|
+
try {
|
|
759
|
+
// Reserve the popup while a direct user gesture is still active. The
|
|
760
|
+
// secure bridge may need a moment to prepare its broker, and opening a
|
|
761
|
+
// window after that await is blocked by browsers with strict popup
|
|
762
|
+
// policies. Navigation happens only after the SDK has registered the
|
|
763
|
+
// exact popup, nonce, and message source below.
|
|
764
|
+
popup = window.open('about:blank', 'einblick-edit-login', popupFeatures);
|
|
738
765
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
766
|
+
catch {
|
|
767
|
+
popup = null;
|
|
768
|
+
}
|
|
769
|
+
try {
|
|
770
|
+
const brokerId = await this.waitForBrokerId();
|
|
771
|
+
if (!brokerId) {
|
|
772
|
+
try {
|
|
773
|
+
popup?.close();
|
|
774
|
+
}
|
|
775
|
+
catch { }
|
|
776
|
+
const message = this.messages.errors.bridgeNotConnected;
|
|
777
|
+
this.callbacks.onError?.(message);
|
|
778
|
+
return false;
|
|
743
779
|
}
|
|
744
|
-
|
|
780
|
+
const loginUrl = this.buildBridgeUrl({
|
|
781
|
+
mode: 'login',
|
|
782
|
+
nonce: loginNonce,
|
|
783
|
+
returnTo,
|
|
784
|
+
});
|
|
785
|
+
if (popup?.closed) {
|
|
745
786
|
popup = null;
|
|
746
787
|
}
|
|
788
|
+
if (!popup) {
|
|
789
|
+
try {
|
|
790
|
+
popup = window.open('about:blank', 'einblick-edit-login', popupFeatures);
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
popup = null;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
747
796
|
if (!popup) {
|
|
748
797
|
window.location.assign(loginUrl);
|
|
749
|
-
|
|
750
|
-
return;
|
|
798
|
+
return false;
|
|
751
799
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
if (this.pendingLogin?.nonce === loginNonce) {
|
|
757
|
-
this.pendingLogin.resolve(false);
|
|
758
|
-
this.pendingLogin = null;
|
|
800
|
+
const loginResult = new Promise((resolve) => {
|
|
801
|
+
const closePollId = window.setInterval(() => {
|
|
802
|
+
if (!popup || popup.closed) {
|
|
803
|
+
this.resolvePendingLogin(loginNonce, false);
|
|
759
804
|
}
|
|
805
|
+
}, 400);
|
|
806
|
+
this.pendingLogin = { nonce: loginNonce, popup, resolve, closePollId };
|
|
807
|
+
});
|
|
808
|
+
try {
|
|
809
|
+
popup.location.assign(loginUrl);
|
|
810
|
+
popup.focus();
|
|
811
|
+
}
|
|
812
|
+
catch {
|
|
813
|
+
this.resolvePendingLogin(loginNonce, false, true);
|
|
814
|
+
window.location.assign(loginUrl);
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
return await loginResult;
|
|
818
|
+
}
|
|
819
|
+
finally {
|
|
820
|
+
this.loginPreparing = false;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
resolvePendingLogin(nonce, result, closePopup = false) {
|
|
824
|
+
const pending = this.pendingLogin;
|
|
825
|
+
if (!pending || pending.nonce !== nonce) {
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
if (pending.closePollId !== null) {
|
|
829
|
+
window.clearInterval(pending.closePollId);
|
|
830
|
+
}
|
|
831
|
+
this.pendingLogin = null;
|
|
832
|
+
if (closePopup) {
|
|
833
|
+
try {
|
|
834
|
+
pending.popup?.close();
|
|
835
|
+
}
|
|
836
|
+
catch { }
|
|
837
|
+
}
|
|
838
|
+
pending.resolve(result);
|
|
839
|
+
return true;
|
|
840
|
+
}
|
|
841
|
+
waitForBrokerId() {
|
|
842
|
+
if (this.brokerId) {
|
|
843
|
+
return Promise.resolve(this.brokerId);
|
|
844
|
+
}
|
|
845
|
+
this.pingBridge();
|
|
846
|
+
return new Promise((resolve) => {
|
|
847
|
+
let settled = false;
|
|
848
|
+
const finish = (brokerId) => {
|
|
849
|
+
if (settled) {
|
|
850
|
+
return;
|
|
760
851
|
}
|
|
761
|
-
|
|
762
|
-
|
|
852
|
+
settled = true;
|
|
853
|
+
window.clearTimeout(timeoutId);
|
|
854
|
+
this.brokerReadyWaiters.delete(finish);
|
|
855
|
+
resolve(brokerId);
|
|
856
|
+
};
|
|
857
|
+
const timeoutId = window.setTimeout(() => finish(null), BRIDGE_CONNECTION_TIMEOUT_MS);
|
|
858
|
+
this.brokerReadyWaiters.add(finish);
|
|
763
859
|
});
|
|
764
860
|
}
|
|
861
|
+
resolveBrokerReadyWaiters(brokerId) {
|
|
862
|
+
for (const resolve of this.brokerReadyWaiters) {
|
|
863
|
+
resolve(brokerId);
|
|
864
|
+
}
|
|
865
|
+
this.brokerReadyWaiters.clear();
|
|
866
|
+
}
|
|
765
867
|
openEditor(binding, element) {
|
|
766
868
|
this.setBrandPopoverOpen(false);
|
|
767
869
|
this.setBottomBarMenuOpen(false);
|
|
@@ -919,14 +1021,24 @@ class EinblickEditRuntime {
|
|
|
919
1021
|
return;
|
|
920
1022
|
}
|
|
921
1023
|
if (data.source === EINBLICK_BRIDGE_SOURCE) {
|
|
1024
|
+
if (event.source !== this.bridgeFrame?.contentWindow) {
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
922
1027
|
this.handleBridgeMessage(data);
|
|
923
1028
|
return;
|
|
924
1029
|
}
|
|
925
1030
|
if (data.source === EINBLICK_AUTH_SOURCE) {
|
|
1031
|
+
if (event.source !== this.pendingLogin?.popup) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
926
1034
|
this.handleAuthMessage(data);
|
|
927
1035
|
return;
|
|
928
1036
|
}
|
|
929
1037
|
if (data.source === EINBLICK_EDITOR_SOURCE) {
|
|
1038
|
+
if (event.source !== this.editorFrame?.contentWindow &&
|
|
1039
|
+
event.source !== this.navigatorFrame?.contentWindow) {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
930
1042
|
this.handleEditorMessage(data);
|
|
931
1043
|
}
|
|
932
1044
|
};
|
|
@@ -936,7 +1048,10 @@ class EinblickEditRuntime {
|
|
|
936
1048
|
}
|
|
937
1049
|
if (message.type === 'bridge-ready') {
|
|
938
1050
|
this.clearBridgePing();
|
|
1051
|
+
this.brokerId = message.brokerId ?? this.brokerId;
|
|
1052
|
+
this.resolveBrokerReadyWaiters(this.brokerId);
|
|
939
1053
|
if (message.authenticated) {
|
|
1054
|
+
this.setSession({ active: true, expiresAt: message.expiresAt });
|
|
940
1055
|
this.setState({
|
|
941
1056
|
enabled: true,
|
|
942
1057
|
active: true,
|
|
@@ -964,6 +1079,26 @@ class EinblickEditRuntime {
|
|
|
964
1079
|
}
|
|
965
1080
|
return;
|
|
966
1081
|
}
|
|
1082
|
+
if (message.type === 'broker-proof-result') {
|
|
1083
|
+
const pending = this.pendingLogin;
|
|
1084
|
+
if (!pending ||
|
|
1085
|
+
message.requestId !== pending.nonce ||
|
|
1086
|
+
message.brokerId !== this.brokerId) {
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
try {
|
|
1090
|
+
pending.popup?.postMessage({
|
|
1091
|
+
source: EINBLICK_AUTH_SOURCE,
|
|
1092
|
+
type: 'broker-proof-result',
|
|
1093
|
+
nonce: pending.nonce,
|
|
1094
|
+
requestId: message.requestId,
|
|
1095
|
+
brokerId: message.brokerId,
|
|
1096
|
+
ciphertext: message.ciphertext,
|
|
1097
|
+
}, this.appOrigin);
|
|
1098
|
+
}
|
|
1099
|
+
catch { }
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
967
1102
|
if (message.type === 'logout-result') {
|
|
968
1103
|
const pending = this.pendingLogout;
|
|
969
1104
|
if (!pending || pending.requestId !== message.requestId) {
|
|
@@ -1011,35 +1146,42 @@ class EinblickEditRuntime {
|
|
|
1011
1146
|
if (!this.pendingLogin || message.nonce !== this.pendingLogin.nonce) {
|
|
1012
1147
|
return;
|
|
1013
1148
|
}
|
|
1014
|
-
if (
|
|
1015
|
-
|
|
1149
|
+
if (message.type === 'broker-proof-request') {
|
|
1150
|
+
if (message.requestId !== this.pendingLogin.nonce ||
|
|
1151
|
+
message.brokerId !== this.brokerId ||
|
|
1152
|
+
!this.bridgeFrame?.contentWindow) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
try {
|
|
1156
|
+
this.bridgeFrame.contentWindow.postMessage({
|
|
1157
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
1158
|
+
type: 'broker-proof-request',
|
|
1159
|
+
nonce: this.bridgeNonce,
|
|
1160
|
+
requestId: message.requestId,
|
|
1161
|
+
brokerId: message.brokerId,
|
|
1162
|
+
publicKey: message.publicKey,
|
|
1163
|
+
}, this.appOrigin);
|
|
1164
|
+
}
|
|
1165
|
+
catch { }
|
|
1166
|
+
return;
|
|
1016
1167
|
}
|
|
1017
1168
|
const pending = this.pendingLogin;
|
|
1018
|
-
this.pendingLogin = null;
|
|
1019
1169
|
if (message.ok) {
|
|
1020
|
-
if (!message.
|
|
1170
|
+
if (!message.brokerId || message.brokerId !== this.brokerId) {
|
|
1021
1171
|
const errorMessage = this.messages.errors.signInDidNotReturnSession;
|
|
1022
1172
|
this.setState({ ...this.state, errorMessage, status: 'error' });
|
|
1023
1173
|
this.callbacks.onError?.(errorMessage);
|
|
1024
|
-
pending.
|
|
1174
|
+
this.resolvePendingLogin(pending.nonce, false, true);
|
|
1025
1175
|
return;
|
|
1026
1176
|
}
|
|
1027
|
-
this.
|
|
1028
|
-
|
|
1029
|
-
expiresAt: message.expiresAt,
|
|
1030
|
-
});
|
|
1031
|
-
try {
|
|
1032
|
-
pending.popup?.close();
|
|
1033
|
-
}
|
|
1034
|
-
catch { }
|
|
1035
|
-
this.reloadBridge();
|
|
1036
|
-
pending.resolve(true);
|
|
1177
|
+
this.pingBridge();
|
|
1178
|
+
this.resolvePendingLogin(pending.nonce, true, true);
|
|
1037
1179
|
return;
|
|
1038
1180
|
}
|
|
1039
1181
|
const errorMessage = message.message || this.messages.errors.signInFailed;
|
|
1040
1182
|
this.setState({ ...this.state, errorMessage, status: 'error' });
|
|
1041
1183
|
this.callbacks.onError?.(errorMessage);
|
|
1042
|
-
pending.
|
|
1184
|
+
this.resolvePendingLogin(pending.nonce, false, true);
|
|
1043
1185
|
}
|
|
1044
1186
|
handleEditorMessage(message) {
|
|
1045
1187
|
if (this.navigatorNonce && message.nonce === this.navigatorNonce) {
|
|
@@ -1133,24 +1275,13 @@ class EinblickEditRuntime {
|
|
|
1133
1275
|
}
|
|
1134
1276
|
}
|
|
1135
1277
|
setSession(session) {
|
|
1136
|
-
const
|
|
1278
|
+
const wasActive = this.session !== null;
|
|
1137
1279
|
this.session = session && !isEditSessionExpired(session) ? session : null;
|
|
1138
|
-
|
|
1139
|
-
if (previousSessionToken !== nextSessionToken) {
|
|
1280
|
+
if (wasActive !== (this.session !== null)) {
|
|
1140
1281
|
this.removeNavigatorPanel(false);
|
|
1141
1282
|
}
|
|
1142
1283
|
this.callbacks.onSessionChange(this.session);
|
|
1143
1284
|
}
|
|
1144
|
-
getActiveSessionToken() {
|
|
1145
|
-
if (!this.session) {
|
|
1146
|
-
return null;
|
|
1147
|
-
}
|
|
1148
|
-
if (isEditSessionExpired(this.session)) {
|
|
1149
|
-
this.setSession(null);
|
|
1150
|
-
return null;
|
|
1151
|
-
}
|
|
1152
|
-
return this.session.sessionToken;
|
|
1153
|
-
}
|
|
1154
1285
|
setState(nextState) {
|
|
1155
1286
|
this.state = nextState;
|
|
1156
1287
|
this.callbacks.onStateChange(nextState);
|
|
@@ -1739,10 +1870,15 @@ class EinblickEditRuntime {
|
|
|
1739
1870
|
}
|
|
1740
1871
|
}
|
|
1741
1872
|
async logoutFromEinblick() {
|
|
1873
|
+
await this.endEditSession(true);
|
|
1874
|
+
}
|
|
1875
|
+
async deactivateEditSession() {
|
|
1876
|
+
await this.endEditSession(false);
|
|
1877
|
+
}
|
|
1878
|
+
async endEditSession(signOut) {
|
|
1742
1879
|
if (typeof window === 'undefined') {
|
|
1743
1880
|
return;
|
|
1744
1881
|
}
|
|
1745
|
-
const sessionToken = this.getActiveSessionToken();
|
|
1746
1882
|
this.setSession(null);
|
|
1747
1883
|
this.setState({
|
|
1748
1884
|
enabled: true,
|
|
@@ -1752,13 +1888,13 @@ class EinblickEditRuntime {
|
|
|
1752
1888
|
siteName: this.state.siteName,
|
|
1753
1889
|
errorMessage: undefined,
|
|
1754
1890
|
});
|
|
1755
|
-
const loggedOutViaBridge = await this.requestBridgeLogout();
|
|
1891
|
+
const loggedOutViaBridge = await this.requestBridgeLogout(signOut);
|
|
1756
1892
|
if (!loggedOutViaBridge) {
|
|
1757
|
-
await this.logoutViaPopup(
|
|
1893
|
+
await this.logoutViaPopup(signOut);
|
|
1758
1894
|
}
|
|
1759
1895
|
this.reloadBridge();
|
|
1760
1896
|
}
|
|
1761
|
-
requestBridgeLogout() {
|
|
1897
|
+
requestBridgeLogout(signOut) {
|
|
1762
1898
|
if (typeof window === 'undefined' || this.pendingLogout) {
|
|
1763
1899
|
return Promise.resolve(false);
|
|
1764
1900
|
}
|
|
@@ -1782,6 +1918,7 @@ class EinblickEditRuntime {
|
|
|
1782
1918
|
type: 'logout',
|
|
1783
1919
|
nonce: this.bridgeNonce,
|
|
1784
1920
|
requestId,
|
|
1921
|
+
signOut,
|
|
1785
1922
|
}, this.appOrigin);
|
|
1786
1923
|
}
|
|
1787
1924
|
catch {
|
|
@@ -1793,12 +1930,12 @@ class EinblickEditRuntime {
|
|
|
1793
1930
|
}
|
|
1794
1931
|
});
|
|
1795
1932
|
}
|
|
1796
|
-
async logoutViaPopup(
|
|
1933
|
+
async logoutViaPopup(signOut) {
|
|
1797
1934
|
const logoutUrl = this.buildBridgeUrl({
|
|
1798
1935
|
mode: 'logout',
|
|
1799
1936
|
nonce: createRandomId(),
|
|
1800
1937
|
returnTo: window.location.href,
|
|
1801
|
-
|
|
1938
|
+
signOut,
|
|
1802
1939
|
});
|
|
1803
1940
|
let popup = null;
|
|
1804
1941
|
try {
|
|
@@ -2046,23 +2183,22 @@ class EinblickEditRuntime {
|
|
|
2046
2183
|
frame.src = this.buildBridgeUrl({ mode: 'bridge', nonce: this.bridgeNonce });
|
|
2047
2184
|
this.bridgeFrame = frame;
|
|
2048
2185
|
document.body.append(frame);
|
|
2049
|
-
const sendPing = () => {
|
|
2050
|
-
if (!this.bridgeFrame?.contentWindow) {
|
|
2051
|
-
return;
|
|
2052
|
-
}
|
|
2053
|
-
try {
|
|
2054
|
-
this.bridgeFrame.contentWindow.postMessage({
|
|
2055
|
-
source: EINBLICK_PARENT_SOURCE,
|
|
2056
|
-
type: 'bridge-ping',
|
|
2057
|
-
nonce: this.bridgeNonce,
|
|
2058
|
-
}, this.appOrigin);
|
|
2059
|
-
}
|
|
2060
|
-
catch { }
|
|
2061
|
-
};
|
|
2062
2186
|
frame.addEventListener('load', () => {
|
|
2063
|
-
|
|
2187
|
+
this.pingBridge();
|
|
2064
2188
|
});
|
|
2065
|
-
this.bridgePingInterval = window.setInterval(
|
|
2189
|
+
this.bridgePingInterval = window.setInterval(() => this.pingBridge(), 1500);
|
|
2190
|
+
}
|
|
2191
|
+
pingBridge() {
|
|
2192
|
+
if (!this.bridgeFrame?.contentWindow)
|
|
2193
|
+
return;
|
|
2194
|
+
try {
|
|
2195
|
+
this.bridgeFrame.contentWindow.postMessage({
|
|
2196
|
+
source: EINBLICK_PARENT_SOURCE,
|
|
2197
|
+
type: 'bridge-ping',
|
|
2198
|
+
nonce: this.bridgeNonce,
|
|
2199
|
+
}, this.appOrigin);
|
|
2200
|
+
}
|
|
2201
|
+
catch { }
|
|
2066
2202
|
}
|
|
2067
2203
|
clearBridgePing() {
|
|
2068
2204
|
if (this.bridgePingInterval !== null) {
|
|
@@ -2075,28 +2211,33 @@ class EinblickEditRuntime {
|
|
|
2075
2211
|
url.searchParams.set('siteKey', this.siteKey);
|
|
2076
2212
|
url.searchParams.set('origin', window.location.origin);
|
|
2077
2213
|
url.searchParams.set('nonce', args.nonce);
|
|
2214
|
+
url.searchParams.set('protocol', '2');
|
|
2215
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
2078
2216
|
if (args.mode !== 'bridge') {
|
|
2079
2217
|
url.searchParams.set('mode', args.mode);
|
|
2080
2218
|
}
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
url.searchParams.set('sessionToken', sessionToken);
|
|
2219
|
+
const brokerId = args.brokerId ?? (args.mode === 'login' ? this.brokerId : null);
|
|
2220
|
+
if (brokerId) {
|
|
2221
|
+
url.searchParams.set('brokerId', brokerId);
|
|
2085
2222
|
}
|
|
2086
2223
|
if (args.returnTo) {
|
|
2087
2224
|
url.searchParams.set('returnTo', args.returnTo);
|
|
2088
2225
|
}
|
|
2226
|
+
if (args.signOut === false) {
|
|
2227
|
+
url.searchParams.set('signOut', '0');
|
|
2228
|
+
}
|
|
2089
2229
|
return url.toString();
|
|
2090
2230
|
}
|
|
2091
2231
|
buildEditorUrl(binding, nonce, intent = 'edit') {
|
|
2092
|
-
|
|
2093
|
-
if (!sessionToken) {
|
|
2232
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
2094
2233
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
2095
2234
|
}
|
|
2096
2235
|
const url = new URL('/sdk/editor', this.appOrigin);
|
|
2097
2236
|
url.searchParams.set('origin', window.location.origin);
|
|
2098
2237
|
url.searchParams.set('nonce', nonce);
|
|
2099
|
-
url.searchParams.set('
|
|
2238
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2239
|
+
url.searchParams.set('protocol', '2');
|
|
2240
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
2100
2241
|
url.searchParams.set('returnTo', window.location.href);
|
|
2101
2242
|
url.searchParams.set('sourceType', binding.sourceType ?? 'cms');
|
|
2102
2243
|
url.searchParams.set('resourceSlug', binding.resourceSlug);
|
|
@@ -2115,25 +2256,27 @@ class EinblickEditRuntime {
|
|
|
2115
2256
|
return url.toString();
|
|
2116
2257
|
}
|
|
2117
2258
|
buildNavigatorUrl(nonce) {
|
|
2118
|
-
|
|
2119
|
-
if (!sessionToken) {
|
|
2259
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
2120
2260
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
2121
2261
|
}
|
|
2122
2262
|
const url = new URL('/sdk/navigator', this.appOrigin);
|
|
2123
2263
|
url.searchParams.set('origin', window.location.origin);
|
|
2124
2264
|
url.searchParams.set('nonce', nonce);
|
|
2125
|
-
url.searchParams.set('
|
|
2265
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2266
|
+
url.searchParams.set('protocol', '2');
|
|
2267
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
2126
2268
|
return url.toString();
|
|
2127
2269
|
}
|
|
2128
2270
|
buildCollectionEditorUrl(args) {
|
|
2129
|
-
|
|
2130
|
-
if (!sessionToken) {
|
|
2271
|
+
if (!this.session || isEditSessionExpired(this.session)) {
|
|
2131
2272
|
throw new Error(this.messages.errors.editSessionExpired);
|
|
2132
2273
|
}
|
|
2133
2274
|
const url = new URL('/sdk/editor', this.appOrigin);
|
|
2134
2275
|
url.searchParams.set('origin', window.location.origin);
|
|
2135
2276
|
url.searchParams.set('nonce', args.nonce);
|
|
2136
|
-
url.searchParams.set('
|
|
2277
|
+
url.searchParams.set('siteKey', this.siteKey);
|
|
2278
|
+
url.searchParams.set('protocol', '2');
|
|
2279
|
+
url.searchParams.set('persist', this.persist ? '1' : '0');
|
|
2137
2280
|
url.searchParams.set('returnTo', window.location.href);
|
|
2138
2281
|
url.searchParams.set('sourceType', args.sourceType ?? 'cms');
|
|
2139
2282
|
url.searchParams.set('collectionId', args.collectionId);
|
|
@@ -2175,6 +2318,62 @@ class EinblickEditRuntime {
|
|
|
2175
2318
|
if (typeof document === 'undefined') {
|
|
2176
2319
|
return;
|
|
2177
2320
|
}
|
|
2321
|
+
for (const [template, control] of this.collectionCreateControls) {
|
|
2322
|
+
if (!template.isConnected || !control.container.isConnected) {
|
|
2323
|
+
control.container.remove();
|
|
2324
|
+
this.collectionCreateControls.delete(template);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
const templates = Array.from(document.querySelectorAll('template[data-einblick-collection-create-template="true"]'));
|
|
2328
|
+
for (const template of templates) {
|
|
2329
|
+
const collection = template.closest('[data-einblick-editable="true"][data-einblick-kind="collection"]');
|
|
2330
|
+
const binding = collection ? readBindingFromElement(collection) : null;
|
|
2331
|
+
const isVisible = !!collection &&
|
|
2332
|
+
!!binding &&
|
|
2333
|
+
this.shouldShowCreateButton(collection, binding);
|
|
2334
|
+
const existing = this.collectionCreateControls.get(template);
|
|
2335
|
+
if (!isVisible || !collection) {
|
|
2336
|
+
if (existing) {
|
|
2337
|
+
existing.container.remove();
|
|
2338
|
+
this.collectionCreateControls.delete(template);
|
|
2339
|
+
}
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
let control = existing;
|
|
2343
|
+
if (!control) {
|
|
2344
|
+
const button = document.createElement('button');
|
|
2345
|
+
button.type = 'button';
|
|
2346
|
+
button.setAttribute('data-einblick-collection-create-button', 'true');
|
|
2347
|
+
button.setAttribute('data-einblick-runtime-created', 'true');
|
|
2348
|
+
const container = collection.tagName === 'UL' || collection.tagName === 'OL'
|
|
2349
|
+
? document.createElement('li')
|
|
2350
|
+
: button;
|
|
2351
|
+
if (container !== button) {
|
|
2352
|
+
container.setAttribute('data-einblick-collection-create-wrapper', 'true');
|
|
2353
|
+
container.append(button);
|
|
2354
|
+
}
|
|
2355
|
+
template.insertAdjacentElement('afterend', container);
|
|
2356
|
+
control = { button, container };
|
|
2357
|
+
this.collectionCreateControls.set(template, control);
|
|
2358
|
+
}
|
|
2359
|
+
const buttonClass = template.dataset.einblickCollectionCreateButtonClass ?? '';
|
|
2360
|
+
if (control.button.className !== buttonClass) {
|
|
2361
|
+
control.button.className = buttonClass;
|
|
2362
|
+
}
|
|
2363
|
+
const explicitLabel = template.dataset.einblickCollectionCreateLabel?.trim();
|
|
2364
|
+
if (explicitLabel) {
|
|
2365
|
+
control.button.dataset.einblickCollectionCreateLabel = explicitLabel;
|
|
2366
|
+
}
|
|
2367
|
+
else {
|
|
2368
|
+
delete control.button.dataset.einblickCollectionCreateLabel;
|
|
2369
|
+
}
|
|
2370
|
+
if (control.container !== control.button) {
|
|
2371
|
+
const wrapperClass = template.dataset.einblickCollectionCreateWrapperClass ?? '';
|
|
2372
|
+
if (control.container.className !== wrapperClass) {
|
|
2373
|
+
control.container.className = wrapperClass;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2178
2377
|
const buttons = Array.from(document.querySelectorAll('[data-einblick-collection-create-button="true"]'));
|
|
2179
2378
|
for (const button of buttons) {
|
|
2180
2379
|
const label = button.dataset.einblickCollectionCreateLabel?.trim() ||
|
|
@@ -2188,6 +2387,13 @@ class EinblickEditRuntime {
|
|
|
2188
2387
|
this.shouldShowCreateButton(collection, binding);
|
|
2189
2388
|
button.hidden = !isVisible;
|
|
2190
2389
|
button.disabled = !isVisible;
|
|
2390
|
+
button.tabIndex = isVisible ? 0 : -1;
|
|
2391
|
+
if (isVisible) {
|
|
2392
|
+
button.removeAttribute('aria-hidden');
|
|
2393
|
+
}
|
|
2394
|
+
else {
|
|
2395
|
+
button.setAttribute('aria-hidden', 'true');
|
|
2396
|
+
}
|
|
2191
2397
|
const wrapper = button.closest('[data-einblick-collection-create-wrapper="true"]');
|
|
2192
2398
|
if (wrapper) {
|
|
2193
2399
|
wrapper.hidden = !isVisible;
|
|
@@ -2195,7 +2401,8 @@ class EinblickEditRuntime {
|
|
|
2195
2401
|
}
|
|
2196
2402
|
}
|
|
2197
2403
|
shouldShowEditButton(element, binding) {
|
|
2198
|
-
if (
|
|
2404
|
+
if (!this.state.isAuthenticated ||
|
|
2405
|
+
element?.dataset.einblickKind === 'collection') {
|
|
2199
2406
|
return false;
|
|
2200
2407
|
}
|
|
2201
2408
|
return isRecordEditableBinding(binding);
|
|
@@ -2718,6 +2925,7 @@ class EinblickEditRuntime {
|
|
|
2718
2925
|
});
|
|
2719
2926
|
document.body.append(backdrop);
|
|
2720
2927
|
this.editorBackdrop = backdrop;
|
|
2928
|
+
this.editorFrame = iframe;
|
|
2721
2929
|
}
|
|
2722
2930
|
openCollectionDrawer(args) {
|
|
2723
2931
|
if (!this.state.isAuthenticated) {
|
|
@@ -2774,6 +2982,7 @@ class EinblickEditRuntime {
|
|
|
2774
2982
|
});
|
|
2775
2983
|
document.body.append(backdrop);
|
|
2776
2984
|
this.editorBackdrop = backdrop;
|
|
2985
|
+
this.editorFrame = iframe;
|
|
2777
2986
|
}
|
|
2778
2987
|
isBottomBarMenuOpen() {
|
|
2779
2988
|
return !!this.bottomBarMoreMenu && !this.bottomBarMoreMenu.hidden;
|
|
@@ -2789,6 +2998,7 @@ class EinblickEditRuntime {
|
|
|
2789
2998
|
closeDrawer() {
|
|
2790
2999
|
this.editorBackdrop?.remove();
|
|
2791
3000
|
this.editorBackdrop = null;
|
|
3001
|
+
this.editorFrame = null;
|
|
2792
3002
|
this.editorNonce = null;
|
|
2793
3003
|
this.editorTarget = null;
|
|
2794
3004
|
this.editorBinding = null;
|
|
@@ -2820,6 +3030,8 @@ export function createEinblickEditRuntime(options) {
|
|
|
2820
3030
|
start: () => runtime.start(),
|
|
2821
3031
|
destroy: () => runtime.destroy(),
|
|
2822
3032
|
login: (loginOptions) => runtime.login(loginOptions),
|
|
3033
|
+
deactivate: () => runtime.deactivateEditSession(),
|
|
3034
|
+
logout: () => runtime.logoutFromEinblick(),
|
|
2823
3035
|
openEditor: (binding, element) => runtime.openEditor(binding, element),
|
|
2824
3036
|
setLocale: (locale) => runtime.setLocale(locale),
|
|
2825
3037
|
setAccentColor: (accentColor) => runtime.setAccentColor(accentColor),
|