pi-interview 0.4.5 → 0.5.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/README.md +91 -10
- package/form/index.html +6 -3
- package/form/script.js +311 -32
- package/form/styles.css +318 -57
- package/form/themes/default-dark.css +7 -1
- package/form/themes/default-light.css +7 -0
- package/form/themes/tufte-dark.css +10 -4
- package/form/themes/tufte-light.css +10 -4
- package/index.ts +118 -12
- package/package.json +7 -1
- package/schema.ts +108 -5
- package/server.ts +238 -12
package/form/script.js
CHANGED
|
@@ -60,6 +60,14 @@
|
|
|
60
60
|
heartbeat: null,
|
|
61
61
|
queuePoll: null,
|
|
62
62
|
};
|
|
63
|
+
function closeWindow() {
|
|
64
|
+
if (window.glimpse && typeof window.glimpse.close === "function") {
|
|
65
|
+
window.glimpse.close();
|
|
66
|
+
} else {
|
|
67
|
+
window.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
let filePickerOpen = false;
|
|
64
72
|
const CLOSE_DELAY = 10;
|
|
65
73
|
const RING_CIRCUMFERENCE = 100.53;
|
|
@@ -162,7 +170,7 @@
|
|
|
162
170
|
|
|
163
171
|
if (closeIn <= 0) {
|
|
164
172
|
clearInterval(timers.countdown);
|
|
165
|
-
cancelInterview("timeout").finally(() =>
|
|
173
|
+
cancelInterview("timeout").finally(() => closeWindow());
|
|
166
174
|
}
|
|
167
175
|
}, 1000);
|
|
168
176
|
}
|
|
@@ -498,6 +506,155 @@
|
|
|
498
506
|
return container;
|
|
499
507
|
}
|
|
500
508
|
|
|
509
|
+
function renderMediaImage(media) {
|
|
510
|
+
const figure = document.createElement("figure");
|
|
511
|
+
figure.className = "media-block media-image";
|
|
512
|
+
|
|
513
|
+
const img = document.createElement("img");
|
|
514
|
+
const isUrl = media.src.startsWith("http://") || media.src.startsWith("https://") || media.src.startsWith("data:");
|
|
515
|
+
img.src = isUrl ? media.src : `/media?path=${encodeURIComponent(media.src)}&session=${encodeURIComponent(sessionToken)}`;
|
|
516
|
+
img.alt = media.alt || "";
|
|
517
|
+
img.loading = "lazy";
|
|
518
|
+
|
|
519
|
+
figure.appendChild(img);
|
|
520
|
+
if (media.caption) {
|
|
521
|
+
const capEl = document.createElement("div");
|
|
522
|
+
capEl.className = "media-caption";
|
|
523
|
+
capEl.textContent = media.caption;
|
|
524
|
+
figure.appendChild(capEl);
|
|
525
|
+
}
|
|
526
|
+
return figure;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function renderMediaTable(media) {
|
|
530
|
+
const t = media.table;
|
|
531
|
+
const wrapper = document.createElement("div");
|
|
532
|
+
wrapper.className = "media-block media-table";
|
|
533
|
+
|
|
534
|
+
const tableScroll = document.createElement("div");
|
|
535
|
+
tableScroll.className = "media-table-scroll";
|
|
536
|
+
|
|
537
|
+
const table = document.createElement("table");
|
|
538
|
+
table.className = "data-table";
|
|
539
|
+
|
|
540
|
+
const thead = document.createElement("thead");
|
|
541
|
+
const headerRow = document.createElement("tr");
|
|
542
|
+
t.headers.forEach(h => {
|
|
543
|
+
const th = document.createElement("th");
|
|
544
|
+
th.textContent = h;
|
|
545
|
+
headerRow.appendChild(th);
|
|
546
|
+
});
|
|
547
|
+
thead.appendChild(headerRow);
|
|
548
|
+
table.appendChild(thead);
|
|
549
|
+
|
|
550
|
+
const tbody = document.createElement("tbody");
|
|
551
|
+
const highlights = new Set(t.highlights || []);
|
|
552
|
+
t.rows.forEach((row, i) => {
|
|
553
|
+
const tr = document.createElement("tr");
|
|
554
|
+
if (highlights.has(i)) tr.classList.add("highlighted-row");
|
|
555
|
+
row.forEach(cell => {
|
|
556
|
+
const td = document.createElement("td");
|
|
557
|
+
td.innerHTML = renderLightMarkdown(cell);
|
|
558
|
+
tr.appendChild(td);
|
|
559
|
+
});
|
|
560
|
+
tbody.appendChild(tr);
|
|
561
|
+
});
|
|
562
|
+
table.appendChild(tbody);
|
|
563
|
+
|
|
564
|
+
tableScroll.appendChild(table);
|
|
565
|
+
wrapper.appendChild(tableScroll);
|
|
566
|
+
|
|
567
|
+
if (media.caption) {
|
|
568
|
+
const capEl = document.createElement("div");
|
|
569
|
+
capEl.className = "media-caption";
|
|
570
|
+
capEl.textContent = media.caption;
|
|
571
|
+
wrapper.appendChild(capEl);
|
|
572
|
+
}
|
|
573
|
+
return wrapper;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function renderMediaChart(media) {
|
|
577
|
+
const wrapper = document.createElement("div");
|
|
578
|
+
wrapper.className = "media-block media-chart";
|
|
579
|
+
|
|
580
|
+
const canvas = document.createElement("canvas");
|
|
581
|
+
canvas.width = 600;
|
|
582
|
+
canvas.height = 300;
|
|
583
|
+
wrapper.appendChild(canvas);
|
|
584
|
+
|
|
585
|
+
if (media.caption) {
|
|
586
|
+
const capEl = document.createElement("div");
|
|
587
|
+
capEl.className = "media-caption";
|
|
588
|
+
capEl.textContent = media.caption;
|
|
589
|
+
wrapper.appendChild(capEl);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
requestAnimationFrame(() => {
|
|
593
|
+
if (typeof Chart === "undefined") return;
|
|
594
|
+
const chartConfig = JSON.parse(JSON.stringify(media.chart));
|
|
595
|
+
chartConfig.options = chartConfig.options || {};
|
|
596
|
+
chartConfig.options.responsive = true;
|
|
597
|
+
chartConfig.options.maintainAspectRatio = true;
|
|
598
|
+
new Chart(canvas, chartConfig);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
return wrapper;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function renderMediaMermaid(media) {
|
|
605
|
+
const wrapper = document.createElement("div");
|
|
606
|
+
wrapper.className = "media-block media-mermaid";
|
|
607
|
+
|
|
608
|
+
const pre = document.createElement("pre");
|
|
609
|
+
pre.className = "mermaid";
|
|
610
|
+
pre.textContent = media.mermaid;
|
|
611
|
+
wrapper.appendChild(pre);
|
|
612
|
+
|
|
613
|
+
if (media.caption) {
|
|
614
|
+
const capEl = document.createElement("div");
|
|
615
|
+
capEl.className = "media-caption";
|
|
616
|
+
capEl.textContent = media.caption;
|
|
617
|
+
wrapper.appendChild(capEl);
|
|
618
|
+
}
|
|
619
|
+
return wrapper;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function renderMediaHtml(media) {
|
|
623
|
+
const wrapper = document.createElement("div");
|
|
624
|
+
wrapper.className = "media-block media-html";
|
|
625
|
+
wrapper.innerHTML = media.html;
|
|
626
|
+
wrapper.querySelectorAll("script").forEach(s => s.remove());
|
|
627
|
+
|
|
628
|
+
if (media.caption) {
|
|
629
|
+
const capEl = document.createElement("div");
|
|
630
|
+
capEl.className = "media-caption";
|
|
631
|
+
capEl.textContent = media.caption;
|
|
632
|
+
wrapper.appendChild(capEl);
|
|
633
|
+
}
|
|
634
|
+
return wrapper;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function renderMediaBlock(media) {
|
|
638
|
+
if (!media || !media.type) return null;
|
|
639
|
+
if (media.maxHeight) {
|
|
640
|
+
const el = renderMediaBlockByType(media);
|
|
641
|
+
if (el) el.style.maxHeight = media.maxHeight;
|
|
642
|
+
return el;
|
|
643
|
+
}
|
|
644
|
+
return renderMediaBlockByType(media);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function renderMediaBlockByType(media) {
|
|
648
|
+
switch (media.type) {
|
|
649
|
+
case "image": return renderMediaImage(media);
|
|
650
|
+
case "table": return renderMediaTable(media);
|
|
651
|
+
case "chart": return renderMediaChart(media);
|
|
652
|
+
case "mermaid": return renderMediaMermaid(media);
|
|
653
|
+
case "html": return renderMediaHtml(media);
|
|
654
|
+
default: return null;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
501
658
|
function isPrintableKey(event) {
|
|
502
659
|
if (event.metaKey || event.ctrlKey || event.altKey) return false;
|
|
503
660
|
return event.key.length === 1;
|
|
@@ -974,7 +1131,10 @@
|
|
|
974
1131
|
}
|
|
975
1132
|
|
|
976
1133
|
function focusQuestion(index, fromDirection = 'next') {
|
|
977
|
-
|
|
1134
|
+
while (index >= 0 && index < nav.cards.length && nav.cards[index].classList.contains('info-panel')) {
|
|
1135
|
+
index += fromDirection === 'prev' ? -1 : 1;
|
|
1136
|
+
}
|
|
1137
|
+
if (index < 0 || index >= nav.cards.length) return false;
|
|
978
1138
|
|
|
979
1139
|
deactivateSubmitArea();
|
|
980
1140
|
|
|
@@ -1005,12 +1165,14 @@
|
|
|
1005
1165
|
textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
|
|
1006
1166
|
}
|
|
1007
1167
|
}
|
|
1008
|
-
|
|
1168
|
+
return true;
|
|
1009
1169
|
}
|
|
1010
1170
|
|
|
1011
1171
|
function nextQuestion() {
|
|
1012
1172
|
if (nav.questionIndex < nav.cards.length - 1) {
|
|
1013
|
-
focusQuestion(nav.questionIndex + 1, 'next')
|
|
1173
|
+
if (!focusQuestion(nav.questionIndex + 1, 'next')) {
|
|
1174
|
+
activateSubmitArea();
|
|
1175
|
+
}
|
|
1014
1176
|
} else {
|
|
1015
1177
|
activateSubmitArea();
|
|
1016
1178
|
}
|
|
@@ -1043,7 +1205,7 @@
|
|
|
1043
1205
|
if (event.key === 'Escape') {
|
|
1044
1206
|
if (!expiredOverlay.classList.contains('hidden')) {
|
|
1045
1207
|
if (timers.countdown) clearInterval(timers.countdown);
|
|
1046
|
-
cancelInterview("user").finally(() =>
|
|
1208
|
+
cancelInterview("user").finally(() => closeWindow());
|
|
1047
1209
|
return;
|
|
1048
1210
|
}
|
|
1049
1211
|
showSessionExpired();
|
|
@@ -1218,21 +1380,43 @@
|
|
|
1218
1380
|
document.addEventListener('keydown', handleQuestionKeydown);
|
|
1219
1381
|
|
|
1220
1382
|
if (nav.cards.length > 0) {
|
|
1221
|
-
setTimeout(() =>
|
|
1383
|
+
setTimeout(() => {
|
|
1384
|
+
if (!focusQuestion(0)) {
|
|
1385
|
+
activateSubmitArea();
|
|
1386
|
+
}
|
|
1387
|
+
}, 100);
|
|
1222
1388
|
}
|
|
1223
1389
|
}
|
|
1224
1390
|
|
|
1225
|
-
function createQuestionCard(question, index) {
|
|
1391
|
+
function createQuestionCard(question, index, badgeNumber) {
|
|
1226
1392
|
const card = document.createElement("section");
|
|
1227
1393
|
card.className = "question-card";
|
|
1228
1394
|
card.setAttribute("role", "listitem");
|
|
1229
1395
|
card.dataset.questionId = question.id;
|
|
1230
1396
|
|
|
1397
|
+
const colors = ['--q-color-1', '--q-color-2', '--q-color-3', '--q-color-4', '--q-color-5', '--q-color-6'];
|
|
1398
|
+
card.style.setProperty('--card-accent', `var(${colors[index % colors.length]})`);
|
|
1399
|
+
card.style.setProperty('--i', String(index));
|
|
1400
|
+
|
|
1401
|
+
if (question.weight === "minor") card.classList.add("weight-minor");
|
|
1402
|
+
if (question.weight === "critical") card.classList.add("weight-critical");
|
|
1403
|
+
|
|
1404
|
+
const header = document.createElement('div');
|
|
1405
|
+
header.className = 'question-header';
|
|
1406
|
+
|
|
1231
1407
|
const title = document.createElement("h2");
|
|
1232
1408
|
title.className = "question-title";
|
|
1233
1409
|
title.id = `q-${question.id}-title`;
|
|
1234
|
-
title.innerHTML =
|
|
1235
|
-
|
|
1410
|
+
title.innerHTML = renderLightMarkdown(question.question);
|
|
1411
|
+
|
|
1412
|
+
if (badgeNumber !== null) {
|
|
1413
|
+
const badge = document.createElement('span');
|
|
1414
|
+
badge.className = 'question-badge';
|
|
1415
|
+
badge.textContent = String(badgeNumber);
|
|
1416
|
+
header.appendChild(badge);
|
|
1417
|
+
}
|
|
1418
|
+
header.appendChild(title);
|
|
1419
|
+
card.appendChild(header);
|
|
1236
1420
|
|
|
1237
1421
|
if (question.context) {
|
|
1238
1422
|
const context = document.createElement("p");
|
|
@@ -1249,6 +1433,32 @@
|
|
|
1249
1433
|
}
|
|
1250
1434
|
}
|
|
1251
1435
|
|
|
1436
|
+
let belowMedia = [];
|
|
1437
|
+
let sideMedia = [];
|
|
1438
|
+
if (question.media) {
|
|
1439
|
+
const mediaList = Array.isArray(question.media) ? question.media : [question.media];
|
|
1440
|
+
const aboveMedia = mediaList.filter(m => !m.position || m.position === "above");
|
|
1441
|
+
belowMedia = mediaList.filter(m => m.position === "below");
|
|
1442
|
+
sideMedia = mediaList.filter(m => m.position === "side");
|
|
1443
|
+
|
|
1444
|
+
aboveMedia.forEach(m => {
|
|
1445
|
+
const el = renderMediaBlock(m);
|
|
1446
|
+
if (el) card.appendChild(el);
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
if (question.type === "info") {
|
|
1451
|
+
card.classList.add("info-panel");
|
|
1452
|
+
belowMedia.forEach(m => {
|
|
1453
|
+
const el = renderMediaBlock(m);
|
|
1454
|
+
if (el) card.appendChild(el);
|
|
1455
|
+
});
|
|
1456
|
+
if (sideMedia.length > 0) {
|
|
1457
|
+
applySideLayout(card, sideMedia);
|
|
1458
|
+
}
|
|
1459
|
+
return card;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1252
1462
|
if (question.type === "single" || question.type === "multi") {
|
|
1253
1463
|
const list = document.createElement("div");
|
|
1254
1464
|
list.className = "option-list";
|
|
@@ -1261,6 +1471,7 @@
|
|
|
1261
1471
|
: recommended
|
|
1262
1472
|
? [recommended]
|
|
1263
1473
|
: [];
|
|
1474
|
+
const shouldPreselect = recommendedList.length > 0 && question.conviction !== "slight";
|
|
1264
1475
|
|
|
1265
1476
|
question.options.forEach((option, optionIndex) => {
|
|
1266
1477
|
const optionLabel = getOptionLabel(option);
|
|
@@ -1289,10 +1500,14 @@
|
|
|
1289
1500
|
text.textContent = optionLabel;
|
|
1290
1501
|
|
|
1291
1502
|
if (recommendedList.includes(optionLabel)) {
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
text.appendChild(
|
|
1503
|
+
const pill = document.createElement("span");
|
|
1504
|
+
pill.className = "recommended-pill";
|
|
1505
|
+
pill.textContent = "Recommended";
|
|
1506
|
+
text.appendChild(pill);
|
|
1507
|
+
|
|
1508
|
+
if (shouldPreselect) {
|
|
1509
|
+
input.checked = true;
|
|
1510
|
+
}
|
|
1296
1511
|
}
|
|
1297
1512
|
|
|
1298
1513
|
label.appendChild(input);
|
|
@@ -1308,6 +1523,7 @@
|
|
|
1308
1523
|
list.appendChild(label);
|
|
1309
1524
|
});
|
|
1310
1525
|
|
|
1526
|
+
|
|
1311
1527
|
const otherLabel = document.createElement("label");
|
|
1312
1528
|
otherLabel.className = "option-item option-other";
|
|
1313
1529
|
const otherCheck = document.createElement("input");
|
|
@@ -1614,9 +1830,40 @@
|
|
|
1614
1830
|
}
|
|
1615
1831
|
});
|
|
1616
1832
|
|
|
1833
|
+
belowMedia.forEach(m => {
|
|
1834
|
+
const el = renderMediaBlock(m);
|
|
1835
|
+
if (el) card.appendChild(el);
|
|
1836
|
+
});
|
|
1837
|
+
|
|
1838
|
+
if (sideMedia.length > 0) {
|
|
1839
|
+
applySideLayout(card, sideMedia);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1617
1842
|
return card;
|
|
1618
1843
|
}
|
|
1619
1844
|
|
|
1845
|
+
function applySideLayout(card, sideMedia) {
|
|
1846
|
+
const grid = document.createElement("div");
|
|
1847
|
+
grid.className = "question-side-layout";
|
|
1848
|
+
|
|
1849
|
+
const mediaCol = document.createElement("div");
|
|
1850
|
+
mediaCol.className = "question-side-media";
|
|
1851
|
+
sideMedia.forEach(m => {
|
|
1852
|
+
const el = renderMediaBlock(m);
|
|
1853
|
+
if (el) mediaCol.appendChild(el);
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1856
|
+
const contentCol = document.createElement("div");
|
|
1857
|
+
contentCol.className = "question-side-content";
|
|
1858
|
+
while (card.firstChild) {
|
|
1859
|
+
contentCol.appendChild(card.firstChild);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
grid.appendChild(mediaCol);
|
|
1863
|
+
grid.appendChild(contentCol);
|
|
1864
|
+
card.appendChild(grid);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1620
1867
|
function loadImage(file) {
|
|
1621
1868
|
return new Promise((resolve, reject) => {
|
|
1622
1869
|
const img = new Image();
|
|
@@ -1748,7 +1995,13 @@
|
|
|
1748
1995
|
if (nav.inSubmitArea || session.expired) return;
|
|
1749
1996
|
const clipboard = event.clipboardData;
|
|
1750
1997
|
if (!clipboard) return;
|
|
1751
|
-
|
|
1998
|
+
|
|
1999
|
+
const active = document.activeElement;
|
|
2000
|
+
const isTextInput = active && (active.tagName === "TEXTAREA" || (active.tagName === "INPUT" && active.type === "text"));
|
|
2001
|
+
if (isTextInput && clipboard.getData("text/plain")) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
1752
2005
|
const context = resolveQuestionContext(event.target);
|
|
1753
2006
|
if (!context) return;
|
|
1754
2007
|
|
|
@@ -1819,22 +2072,23 @@
|
|
|
1819
2072
|
}
|
|
1820
2073
|
|
|
1821
2074
|
function collectResponses() {
|
|
1822
|
-
return questions
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
const
|
|
1826
|
-
if (
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2075
|
+
return questions
|
|
2076
|
+
.filter((question) => question.type !== "info")
|
|
2077
|
+
.map((question) => {
|
|
2078
|
+
const resp = { id: question.id, value: getQuestionValue(question) };
|
|
2079
|
+
if (question.type !== "image") {
|
|
2080
|
+
const attachPaths = attachments.getPaths(question.id);
|
|
2081
|
+
if (attachPaths.length > 0) resp.attachments = attachPaths;
|
|
2082
|
+
}
|
|
2083
|
+
return resp;
|
|
2084
|
+
});
|
|
1830
2085
|
}
|
|
1831
2086
|
|
|
1832
2087
|
function collectPersistedData() {
|
|
1833
2088
|
const data = {};
|
|
1834
2089
|
questions.forEach((question) => {
|
|
1835
|
-
if (question.type
|
|
1836
|
-
|
|
1837
|
-
}
|
|
2090
|
+
if (question.type === "info" || question.type === "image") return;
|
|
2091
|
+
data[question.id] = getQuestionValue(question);
|
|
1838
2092
|
});
|
|
1839
2093
|
return data;
|
|
1840
2094
|
}
|
|
@@ -1924,19 +2178,28 @@
|
|
|
1924
2178
|
|
|
1925
2179
|
function loadProgress() {
|
|
1926
2180
|
if (!session.storageKey) return;
|
|
2181
|
+
let loaded = false;
|
|
1927
2182
|
try {
|
|
1928
2183
|
const saved = localStorage.getItem(session.storageKey);
|
|
1929
2184
|
if (saved) {
|
|
1930
2185
|
populateForm(JSON.parse(saved));
|
|
1931
2186
|
questions.forEach((q) => {
|
|
1932
|
-
if (q.type === "multi")
|
|
1933
|
-
updateDoneState(q.id);
|
|
1934
|
-
}
|
|
2187
|
+
if (q.type === "multi") updateDoneState(q.id);
|
|
1935
2188
|
});
|
|
2189
|
+
loaded = true;
|
|
1936
2190
|
}
|
|
1937
2191
|
} catch (_err) {
|
|
1938
2192
|
// ignore storage errors
|
|
1939
2193
|
}
|
|
2194
|
+
if (!loaded) {
|
|
2195
|
+
questions.forEach(q => {
|
|
2196
|
+
if (q.type !== "multi") return;
|
|
2197
|
+
const recs = Array.isArray(q.recommended) ? q.recommended : q.recommended ? [q.recommended] : [];
|
|
2198
|
+
if (recs.length > 0 && q.conviction !== "slight") {
|
|
2199
|
+
updateDoneState(q.id);
|
|
2200
|
+
}
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
1940
2203
|
}
|
|
1941
2204
|
|
|
1942
2205
|
function clearProgress() {
|
|
@@ -2166,7 +2429,7 @@
|
|
|
2166
2429
|
session.ended = true;
|
|
2167
2430
|
successOverlay.classList.remove("hidden");
|
|
2168
2431
|
setTimeout(() => {
|
|
2169
|
-
|
|
2432
|
+
closeWindow();
|
|
2170
2433
|
}, 800);
|
|
2171
2434
|
} catch (err) {
|
|
2172
2435
|
if (isNetworkError(err)) {
|
|
@@ -2205,8 +2468,11 @@
|
|
|
2205
2468
|
const shortId = sessionId.slice(0, 8);
|
|
2206
2469
|
document.title = `${projectName}${gitBranch ? ` (${gitBranch})` : ""} | ${shortId}`;
|
|
2207
2470
|
|
|
2471
|
+
let badgeCount = 0;
|
|
2208
2472
|
questions.forEach((question, index) => {
|
|
2209
|
-
|
|
2473
|
+
const showBadge = question.type !== "info";
|
|
2474
|
+
if (showBadge) badgeCount++;
|
|
2475
|
+
containerEl.appendChild(createQuestionCard(question, index, showBadge ? badgeCount : null));
|
|
2210
2476
|
});
|
|
2211
2477
|
|
|
2212
2478
|
// Pre-populate: savedAnswers takes precedence over localStorage
|
|
@@ -2248,7 +2514,10 @@
|
|
|
2248
2514
|
if (!url) return;
|
|
2249
2515
|
const selectedOption = queueSessionSelect.options[queueSessionSelect.selectedIndex];
|
|
2250
2516
|
if (selectedOption?.disabled) return;
|
|
2251
|
-
window.open(url, "_blank", "noopener");
|
|
2517
|
+
const opened = window.open(url, "_blank", "noopener");
|
|
2518
|
+
if (!opened) {
|
|
2519
|
+
window.location.href = url;
|
|
2520
|
+
}
|
|
2252
2521
|
});
|
|
2253
2522
|
}
|
|
2254
2523
|
window.addEventListener("pagehide", (event) => {
|
|
@@ -2281,7 +2550,7 @@
|
|
|
2281
2550
|
closeTabBtn.addEventListener("click", async () => {
|
|
2282
2551
|
if (timers.countdown) clearInterval(timers.countdown);
|
|
2283
2552
|
await cancelInterview("user");
|
|
2284
|
-
|
|
2553
|
+
closeWindow();
|
|
2285
2554
|
});
|
|
2286
2555
|
|
|
2287
2556
|
stayBtn.addEventListener("click", () => {
|
|
@@ -2328,6 +2597,16 @@
|
|
|
2328
2597
|
}
|
|
2329
2598
|
|
|
2330
2599
|
initQuestionNavigation();
|
|
2600
|
+
|
|
2601
|
+
if (typeof mermaid !== "undefined") {
|
|
2602
|
+
const isDark = document.documentElement.dataset.theme === "dark" ||
|
|
2603
|
+
(!document.documentElement.dataset.theme && window.matchMedia("(prefers-color-scheme: dark)").matches);
|
|
2604
|
+
mermaid.initialize({
|
|
2605
|
+
startOnLoad: false,
|
|
2606
|
+
theme: isDark ? "dark" : "default",
|
|
2607
|
+
});
|
|
2608
|
+
mermaid.run();
|
|
2609
|
+
}
|
|
2331
2610
|
}
|
|
2332
2611
|
|
|
2333
2612
|
window.__INTERVIEW_API__ = {
|