@tn3w/openage 1.0.4 → 1.0.6
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 +26 -6
- package/dist/openage.esm.js +276 -28
- package/dist/openage.esm.js.map +1 -1
- package/dist/openage.min.js +1 -1
- package/dist/openage.min.js.map +1 -1
- package/dist/openage.umd.js +276 -28
- package/dist/openage.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/challenge.js +86 -14
- package/src/constants.d.ts +1 -0
- package/src/constants.js +4 -4
- package/src/index.d.ts +1 -0
- package/src/index.js +17 -0
- package/src/ui.d.ts +4 -0
- package/src/ui.js +71 -0
- package/src/widget.d.ts +2 -0
- package/src/widget.js +100 -10
package/dist/openage.umd.js
CHANGED
|
@@ -547,6 +547,20 @@
|
|
|
547
547
|
flex-direction: column;
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
+
.oa-inline-shell {
|
|
551
|
+
background: var(--oa-bg);
|
|
552
|
+
border: 1px solid var(--oa-border);
|
|
553
|
+
border-radius: var(--oa-radius);
|
|
554
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.18),
|
|
555
|
+
0 0 0 1px rgba(0,0,0,0.06);
|
|
556
|
+
width: min(100%, 360px);
|
|
557
|
+
max-width: 100%;
|
|
558
|
+
overflow: hidden;
|
|
559
|
+
display: flex;
|
|
560
|
+
flex-direction: column;
|
|
561
|
+
margin: 0 auto;
|
|
562
|
+
}
|
|
563
|
+
|
|
550
564
|
.oa-modal-overlay {
|
|
551
565
|
position: fixed;
|
|
552
566
|
inset: 0;
|
|
@@ -899,6 +913,52 @@
|
|
|
899
913
|
.oa-result-fail { color: var(--oa-danger); }
|
|
900
914
|
.oa-result-retry { color: var(--oa-warn); }
|
|
901
915
|
|
|
916
|
+
.oa-error-step {
|
|
917
|
+
display: flex;
|
|
918
|
+
flex-direction: column;
|
|
919
|
+
align-items: center;
|
|
920
|
+
gap: 0.7rem;
|
|
921
|
+
padding: 2rem 1.2rem;
|
|
922
|
+
background: var(--oa-surface);
|
|
923
|
+
border: 1px solid var(--oa-border);
|
|
924
|
+
border-radius: var(--oa-radius);
|
|
925
|
+
margin: 10px;
|
|
926
|
+
animation: oa-fade-in 0.4s ease;
|
|
927
|
+
text-align: center;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.oa-error-step-icon {
|
|
931
|
+
width: 3rem;
|
|
932
|
+
height: 3rem;
|
|
933
|
+
display: flex;
|
|
934
|
+
align-items: center;
|
|
935
|
+
justify-content: center;
|
|
936
|
+
border-radius: 999px;
|
|
937
|
+
background: rgba(239, 68, 68, 0.12);
|
|
938
|
+
color: var(--oa-danger);
|
|
939
|
+
font-size: 1.7rem;
|
|
940
|
+
line-height: 1;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.oa-error-step-title {
|
|
944
|
+
font-size: 1rem;
|
|
945
|
+
font-weight: 700;
|
|
946
|
+
color: var(--oa-text);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.oa-error-step-message {
|
|
950
|
+
font-size: 0.84rem;
|
|
951
|
+
line-height: 1.5;
|
|
952
|
+
color: var(--oa-text-muted);
|
|
953
|
+
max-width: 260px;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
.oa-error-step-countdown {
|
|
957
|
+
font-size: 0.75rem;
|
|
958
|
+
font-weight: 600;
|
|
959
|
+
color: var(--oa-danger);
|
|
960
|
+
}
|
|
961
|
+
|
|
902
962
|
.oa-hidden { display: none !important; }
|
|
903
963
|
|
|
904
964
|
/* ── Animations ──────────────────────────────── */
|
|
@@ -1025,6 +1085,17 @@
|
|
|
1025
1085
|
`;
|
|
1026
1086
|
}
|
|
1027
1087
|
|
|
1088
|
+
function errorStepTemplate(message) {
|
|
1089
|
+
return `
|
|
1090
|
+
<div class="oa-error-step">
|
|
1091
|
+
<div class="oa-error-step-icon">✕</div>
|
|
1092
|
+
<div class="oa-error-step-title">Verification stopped</div>
|
|
1093
|
+
<div class="oa-error-step-message">${message}</div>
|
|
1094
|
+
<div class="oa-error-step-countdown"></div>
|
|
1095
|
+
</div>
|
|
1096
|
+
`;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1028
1099
|
function resultTemplate(outcome, message) {
|
|
1029
1100
|
const icons = {
|
|
1030
1101
|
fail: '✕',
|
|
@@ -1046,7 +1117,7 @@
|
|
|
1046
1117
|
|
|
1047
1118
|
const VERSION = '1.0.0';
|
|
1048
1119
|
|
|
1049
|
-
const MEDIAPIPE_CDN = 'https://cdn.jsdelivr.net/npm
|
|
1120
|
+
const MEDIAPIPE_CDN = 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.17';
|
|
1050
1121
|
|
|
1051
1122
|
const MEDIAPIPE_WASM = `${MEDIAPIPE_CDN}/wasm`;
|
|
1052
1123
|
|
|
@@ -1057,13 +1128,13 @@
|
|
|
1057
1128
|
'face_landmarker/face_landmarker/float16/1/' +
|
|
1058
1129
|
'face_landmarker.task';
|
|
1059
1130
|
|
|
1060
|
-
const FACEAPI_CDN =
|
|
1061
|
-
'https://cdn.jsdelivr.net/npm/' + 'face-api.js@0.22.2/dist/face-api.min.js';
|
|
1131
|
+
const FACEAPI_CDN = 'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js';
|
|
1062
1132
|
|
|
1063
1133
|
const FACEAPI_MODEL_CDN =
|
|
1064
|
-
'https://cdn.jsdelivr.net/gh/
|
|
1134
|
+
'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js@master/weights';
|
|
1065
1135
|
|
|
1066
1136
|
const MAX_RETRIES = 3;
|
|
1137
|
+
const ERROR_STEP_SECONDS = 5;
|
|
1067
1138
|
const BURST_FRAMES = 5;
|
|
1068
1139
|
const BURST_INTERVAL_MS = 200;
|
|
1069
1140
|
const POSITION_CHECK_MS = 100;
|
|
@@ -1094,6 +1165,7 @@
|
|
|
1094
1165
|
this.popup = null;
|
|
1095
1166
|
this.shadow = null;
|
|
1096
1167
|
this.elements = {};
|
|
1168
|
+
this.popupElements = null;
|
|
1097
1169
|
this.onChallenge = null;
|
|
1098
1170
|
this.onStartClick = null;
|
|
1099
1171
|
this.popupFrame = 0;
|
|
@@ -1106,6 +1178,7 @@
|
|
|
1106
1178
|
const host = document.createElement('div');
|
|
1107
1179
|
host.id = this.id;
|
|
1108
1180
|
this.shadow = host.attachShadow({ mode: 'open' });
|
|
1181
|
+
this.host = host;
|
|
1109
1182
|
|
|
1110
1183
|
const style = document.createElement('style');
|
|
1111
1184
|
style.textContent = STYLES;
|
|
@@ -1118,7 +1191,12 @@
|
|
|
1118
1191
|
if (this.params.size === 'invisible') {
|
|
1119
1192
|
host.style.display = 'none';
|
|
1120
1193
|
this.container.appendChild(host);
|
|
1121
|
-
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (this.isInlineLayout()) {
|
|
1198
|
+
this.renderInlineShell();
|
|
1199
|
+
this.container.appendChild(host);
|
|
1122
1200
|
return;
|
|
1123
1201
|
}
|
|
1124
1202
|
|
|
@@ -1154,7 +1232,32 @@
|
|
|
1154
1232
|
this.elements.errorSlot = this.shadow.querySelector('.oa-error-slot');
|
|
1155
1233
|
|
|
1156
1234
|
this.container.appendChild(host);
|
|
1157
|
-
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
isInlineLayout() {
|
|
1238
|
+
return this.params.layout === 'inline';
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
renderInlineShell() {
|
|
1242
|
+
const inlineShell = document.createElement('div');
|
|
1243
|
+
inlineShell.className = 'oa-inline-shell';
|
|
1244
|
+
inlineShell.innerHTML = this.buildPopupContent({ closeable: false });
|
|
1245
|
+
this.shadow.appendChild(inlineShell);
|
|
1246
|
+
|
|
1247
|
+
this.popup = {
|
|
1248
|
+
host: this.host,
|
|
1249
|
+
root: inlineShell,
|
|
1250
|
+
inline: true,
|
|
1251
|
+
};
|
|
1252
|
+
|
|
1253
|
+
this.bindPopupEvents(inlineShell);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
resetInlineShell() {
|
|
1257
|
+
if (!this.popup?.root) return;
|
|
1258
|
+
|
|
1259
|
+
this.popup.root.innerHTML = this.buildPopupContent({ closeable: false });
|
|
1260
|
+
this.bindPopupEvents(this.popup.root);
|
|
1158
1261
|
}
|
|
1159
1262
|
|
|
1160
1263
|
startChallenge() {
|
|
@@ -1187,6 +1290,14 @@
|
|
|
1187
1290
|
}
|
|
1188
1291
|
|
|
1189
1292
|
openPopup() {
|
|
1293
|
+
if (this.isInlineLayout()) {
|
|
1294
|
+
if (!this.popup) {
|
|
1295
|
+
this.renderInlineShell();
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
return this.getVideo();
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1190
1301
|
if (this.popup) return this.getVideo();
|
|
1191
1302
|
|
|
1192
1303
|
const anchor = this.getPopupAnchor();
|
|
@@ -1364,7 +1475,7 @@
|
|
|
1364
1475
|
this.popup.root.style.pointerEvents = 'auto';
|
|
1365
1476
|
}
|
|
1366
1477
|
|
|
1367
|
-
buildPopupContent() {
|
|
1478
|
+
buildPopupContent({ closeable = true } = {}) {
|
|
1368
1479
|
return `
|
|
1369
1480
|
<div class="oa-header">
|
|
1370
1481
|
<div class="oa-title">
|
|
@@ -1375,10 +1486,14 @@
|
|
|
1375
1486
|
</a>
|
|
1376
1487
|
<span class="oa-badge">on-device</span>
|
|
1377
1488
|
</div>
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1489
|
+
${
|
|
1490
|
+
closeable
|
|
1491
|
+
? `<button class="oa-close-btn"
|
|
1492
|
+
aria-label="Close">
|
|
1493
|
+
${CLOSE_SVG}
|
|
1494
|
+
</button>`
|
|
1495
|
+
: ''
|
|
1496
|
+
}
|
|
1382
1497
|
</div>
|
|
1383
1498
|
<div class="oa-body">
|
|
1384
1499
|
${heroTemplate('Initializing…')}
|
|
@@ -1391,7 +1506,7 @@
|
|
|
1391
1506
|
`;
|
|
1392
1507
|
}
|
|
1393
1508
|
|
|
1394
|
-
bindPopupEvents(root
|
|
1509
|
+
bindPopupEvents(root) {
|
|
1395
1510
|
const closeBtn = root.querySelector('.oa-close-btn');
|
|
1396
1511
|
if (closeBtn) {
|
|
1397
1512
|
closeBtn.addEventListener('click', () => {
|
|
@@ -1509,6 +1624,22 @@
|
|
|
1509
1624
|
}
|
|
1510
1625
|
|
|
1511
1626
|
showResult(outcome, message) {
|
|
1627
|
+
if (this.isInlineLayout()) {
|
|
1628
|
+
if (!this.popupElements?.body) return;
|
|
1629
|
+
|
|
1630
|
+
this.popupElements.body.innerHTML = resultTemplate(outcome, message);
|
|
1631
|
+
this.hideActions();
|
|
1632
|
+
|
|
1633
|
+
if (outcome === 'pass') {
|
|
1634
|
+
this.setState('verified');
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
this.setState(outcome === 'fail' ? 'failed' : 'retry');
|
|
1639
|
+
this.showActions('Try Again');
|
|
1640
|
+
return;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1512
1643
|
if (outcome === 'pass') {
|
|
1513
1644
|
this.closePopup();
|
|
1514
1645
|
this.setState('verified');
|
|
@@ -1544,8 +1675,21 @@
|
|
|
1544
1675
|
}
|
|
1545
1676
|
}
|
|
1546
1677
|
|
|
1547
|
-
showError() {
|
|
1548
|
-
this.
|
|
1678
|
+
showError(message) {
|
|
1679
|
+
if (!this.popupElements?.body) return;
|
|
1680
|
+
|
|
1681
|
+
this.popupElements.body.innerHTML = errorStepTemplate(message);
|
|
1682
|
+
this.popupElements.errorCountdown = this.popupElements.body.querySelector(
|
|
1683
|
+
'.oa-error-step-countdown'
|
|
1684
|
+
);
|
|
1685
|
+
this.hideActions();
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
setErrorCountdown(seconds) {
|
|
1689
|
+
if (!this.popupElements?.errorCountdown) return;
|
|
1690
|
+
|
|
1691
|
+
const unit = seconds === 1 ? 'second' : 'seconds';
|
|
1692
|
+
this.popupElements.errorCountdown.textContent = `Closing in ${seconds} ${unit}…`;
|
|
1549
1693
|
}
|
|
1550
1694
|
|
|
1551
1695
|
clearError() {
|
|
@@ -1556,6 +1700,22 @@
|
|
|
1556
1700
|
|
|
1557
1701
|
closePopup() {
|
|
1558
1702
|
if (!this.popup) return;
|
|
1703
|
+
|
|
1704
|
+
if (this.popup.inline) {
|
|
1705
|
+
this.popup.cleanup?.();
|
|
1706
|
+
if (this.popupFrame) {
|
|
1707
|
+
cancelAnimationFrame(this.popupFrame);
|
|
1708
|
+
this.popupFrame = 0;
|
|
1709
|
+
}
|
|
1710
|
+
this.resetInlineShell();
|
|
1711
|
+
|
|
1712
|
+
if (this.state === 'loading') {
|
|
1713
|
+
this.setState('idle');
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1559
1719
|
this.popup.cleanup?.();
|
|
1560
1720
|
this.popup.themeCleanup?.();
|
|
1561
1721
|
this.popup.host.remove();
|
|
@@ -2723,6 +2883,73 @@
|
|
|
2723
2883
|
return new Promise((r) => setTimeout(r, ms));
|
|
2724
2884
|
}
|
|
2725
2885
|
|
|
2886
|
+
function resolveChallengeErrorMessage(error) {
|
|
2887
|
+
const name = typeof error?.name === 'string' ? error.name : '';
|
|
2888
|
+
const message = typeof error?.message === 'string' ? error.message : String(error || '');
|
|
2889
|
+
const normalized = `${name} ${message}`.toLowerCase();
|
|
2890
|
+
|
|
2891
|
+
if (
|
|
2892
|
+
name === 'NotFoundError' ||
|
|
2893
|
+
/request is not allowed by the user agent or the platform in the current context/.test(
|
|
2894
|
+
normalized
|
|
2895
|
+
) ||
|
|
2896
|
+
/requested device not found|device not found|no camera|could not start video source/.test(
|
|
2897
|
+
normalized
|
|
2898
|
+
)
|
|
2899
|
+
) {
|
|
2900
|
+
return 'No camera available. Plug in a camera and try again.';
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
if (
|
|
2904
|
+
name === 'NotAllowedError' ||
|
|
2905
|
+
name === 'PermissionDeniedError' ||
|
|
2906
|
+
/permission|camera access|access denied/.test(normalized)
|
|
2907
|
+
) {
|
|
2908
|
+
return 'Camera access was blocked. Allow camera access and try again.';
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
if (/positioning timeout/.test(normalized)) {
|
|
2912
|
+
return 'Face positioning timed out. Reopen the check and try again.';
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
return 'Verification failed. Please try again.';
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
function isInlineLayout(widget) {
|
|
2919
|
+
return widget?.params?.layout === 'inline';
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
async function showErrorStep(widget, error) {
|
|
2923
|
+
const message = resolveChallengeErrorMessage(error);
|
|
2924
|
+
|
|
2925
|
+
if (isInlineLayout(widget)) {
|
|
2926
|
+
widget.showResult?.('retry', message);
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
if (!widget.popup) {
|
|
2931
|
+
widget.openPopup?.();
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
widget.showError?.(message);
|
|
2935
|
+
|
|
2936
|
+
for (let seconds = ERROR_STEP_SECONDS; seconds > 0; seconds--) {
|
|
2937
|
+
if (!widget.popup) break;
|
|
2938
|
+
widget.setErrorCountdown?.(seconds);
|
|
2939
|
+
await sleep(1000);
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
widget.closePopup?.();
|
|
2943
|
+
widget.setState?.('retry');
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
async function handleChallengeError(widget, emitter, error) {
|
|
2947
|
+
console.log('Error during challenge:', error);
|
|
2948
|
+
await showErrorStep(widget, error);
|
|
2949
|
+
emitter.emit('error', error, widget.id);
|
|
2950
|
+
widget.params.errorCallback?.(error);
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2726
2953
|
async function runChallenge(widget, emitter) {
|
|
2727
2954
|
const mode = widget.params.mode || 'serverless';
|
|
2728
2955
|
|
|
@@ -2752,10 +2979,14 @@
|
|
|
2752
2979
|
await Promise.all([loadVision(), initAgeEstimator()]);
|
|
2753
2980
|
|
|
2754
2981
|
modelBuffer = await loadModel();
|
|
2755
|
-
widget.showReady();
|
|
2756
2982
|
|
|
2757
|
-
|
|
2758
|
-
|
|
2983
|
+
if (isInlineLayout(widget)) {
|
|
2984
|
+
await startCameraFlow(widget, modelBuffer);
|
|
2985
|
+
} else {
|
|
2986
|
+
widget.showReady();
|
|
2987
|
+
await waitForStart(widget);
|
|
2988
|
+
await startCameraFlow(widget, modelBuffer);
|
|
2989
|
+
}
|
|
2759
2990
|
|
|
2760
2991
|
const transport = createTransport('serverless', params);
|
|
2761
2992
|
|
|
@@ -2803,10 +3034,7 @@
|
|
|
2803
3034
|
emitResult(widget, emitter, result);
|
|
2804
3035
|
} catch (error) {
|
|
2805
3036
|
cleanupLocal();
|
|
2806
|
-
|
|
2807
|
-
widget.showResult('fail', 'Verification failed');
|
|
2808
|
-
emitter.emit('error', error, widget.id);
|
|
2809
|
-
params.errorCallback?.(error);
|
|
3037
|
+
await handleChallengeError(widget, emitter, error);
|
|
2810
3038
|
}
|
|
2811
3039
|
}
|
|
2812
3040
|
|
|
@@ -2847,10 +3075,16 @@
|
|
|
2847
3075
|
captureFrame: () => (captureFrame() ? 'true' : 'null'),
|
|
2848
3076
|
});
|
|
2849
3077
|
|
|
2850
|
-
|
|
2851
|
-
|
|
3078
|
+
let video;
|
|
3079
|
+
|
|
3080
|
+
if (isInlineLayout(widget)) {
|
|
3081
|
+
video = widget.showCamera();
|
|
3082
|
+
} else {
|
|
3083
|
+
widget.showReady();
|
|
3084
|
+
await waitForStart(widget);
|
|
3085
|
+
video = widget.showCamera();
|
|
3086
|
+
}
|
|
2852
3087
|
|
|
2853
|
-
const video = widget.showCamera();
|
|
2854
3088
|
widget.setVideoStatus('Requesting camera…');
|
|
2855
3089
|
await startCamera(video);
|
|
2856
3090
|
exposeMirrorVideo(video);
|
|
@@ -2937,11 +3171,8 @@
|
|
|
2937
3171
|
|
|
2938
3172
|
cleanupVM(transport);
|
|
2939
3173
|
} catch (error) {
|
|
2940
|
-
console.log('Error during challenge:', error);
|
|
2941
3174
|
cleanupVM();
|
|
2942
|
-
widget
|
|
2943
|
-
emitter.emit('error', error, widget.id);
|
|
2944
|
-
params.errorCallback?.(error);
|
|
3175
|
+
await handleChallengeError(widget, emitter, error);
|
|
2945
3176
|
}
|
|
2946
3177
|
}
|
|
2947
3178
|
|
|
@@ -3156,8 +3387,19 @@
|
|
|
3156
3387
|
const emitter = new EventEmitter();
|
|
3157
3388
|
const widgets = new Map();
|
|
3158
3389
|
|
|
3390
|
+
function normalizeLayout(layout) {
|
|
3391
|
+
if (layout === 'inline' || layout === 'embed' || layout === 'embedded') {
|
|
3392
|
+
return 'inline';
|
|
3393
|
+
}
|
|
3394
|
+
|
|
3395
|
+
return 'widget';
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3159
3398
|
function normalizeParams(params) {
|
|
3160
3399
|
const globalConfig = typeof window !== 'undefined' ? window.openage || {} : {};
|
|
3400
|
+
const layout = normalizeLayout(
|
|
3401
|
+
params.layout ?? params.display ?? globalConfig.layout ?? globalConfig.display
|
|
3402
|
+
);
|
|
3161
3403
|
|
|
3162
3404
|
return {
|
|
3163
3405
|
mode: 'serverless',
|
|
@@ -3166,6 +3408,7 @@
|
|
|
3166
3408
|
minAge: 18,
|
|
3167
3409
|
...globalConfig,
|
|
3168
3410
|
...params,
|
|
3411
|
+
layout,
|
|
3169
3412
|
};
|
|
3170
3413
|
}
|
|
3171
3414
|
|
|
@@ -3174,6 +3417,10 @@
|
|
|
3174
3417
|
emitter.emit('opened', widget.id);
|
|
3175
3418
|
runChallenge(widget, emitter);
|
|
3176
3419
|
};
|
|
3420
|
+
|
|
3421
|
+
if (widget.params.layout === 'inline') {
|
|
3422
|
+
widget.startChallenge();
|
|
3423
|
+
}
|
|
3177
3424
|
}
|
|
3178
3425
|
|
|
3179
3426
|
function render(container, params = {}) {
|
|
@@ -3322,6 +3569,7 @@
|
|
|
3322
3569
|
size: element.dataset.size,
|
|
3323
3570
|
action: element.dataset.action,
|
|
3324
3571
|
mode: element.dataset.mode,
|
|
3572
|
+
layout: element.dataset.layout || element.dataset.display,
|
|
3325
3573
|
server: element.dataset.server,
|
|
3326
3574
|
};
|
|
3327
3575
|
|