@unvired/turboforms-embed-sdk 1.0.10 → 1.0.12
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 +74 -15
- package/dist/unvired-form-sdk.html +634 -258
- package/dist/unvired-forms-sdk.js +1885 -597
- package/package.json +1 -1
|
@@ -141,7 +141,7 @@ function sendEventCallback({
|
|
|
141
141
|
if (type === "ERROR") {
|
|
142
142
|
eventStructure = {
|
|
143
143
|
type: "ERROR",
|
|
144
|
-
errorMessage,
|
|
144
|
+
errorMessage: errorMessage + ", contact your admin or tech team",
|
|
145
145
|
data
|
|
146
146
|
};
|
|
147
147
|
} else {
|
|
@@ -223,11 +223,11 @@ async function validateAttachments(template, submissionData, sendEventCallback2)
|
|
|
223
223
|
if (typeof fileId === "string" && fileId.trim()) {
|
|
224
224
|
try {
|
|
225
225
|
const fileRecord = await getFileFromIndexedDB(fileId);
|
|
226
|
-
if (!fileRecord || !fileRecord.id || !fileRecord.data
|
|
226
|
+
if (!fileRecord || !fileRecord.id || !fileRecord.data && !fileRecord.url) {
|
|
227
227
|
missingFiles.push({
|
|
228
228
|
fileId,
|
|
229
229
|
field: key,
|
|
230
|
-
reason: fileRecord ? "Incomplete file record (missing id
|
|
230
|
+
reason: fileRecord ? "Incomplete file record (missing id and data/url)" : "File not found in IndexedDB"
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
233
|
} catch (err) {
|
|
@@ -281,6 +281,7 @@ function getFileFromIndexedDB(fileId) {
|
|
|
281
281
|
// src/lib/FileProcessor.js
|
|
282
282
|
async function processFileIds(data, sendEventCallback2) {
|
|
283
283
|
if (!data || typeof data !== "object") return data;
|
|
284
|
+
const clonedData = JSON.parse(JSON.stringify(data));
|
|
284
285
|
async function traverse(obj) {
|
|
285
286
|
for (const key in obj) {
|
|
286
287
|
const value = obj[key];
|
|
@@ -298,21 +299,12 @@ async function processFileIds(data, sendEventCallback2) {
|
|
|
298
299
|
type: fileObject.type,
|
|
299
300
|
url: fileObject.url,
|
|
300
301
|
key,
|
|
301
|
-
uid: value[i]
|
|
302
|
+
uid: value[i],
|
|
303
|
+
mode: fileObject.mode || "G"
|
|
304
|
+
// Fix: Preserve the mode or default to G
|
|
302
305
|
});
|
|
303
306
|
} else {
|
|
304
307
|
console.warn(`File not found in IndexedDB: ${value[i]} - removing from submission data`);
|
|
305
|
-
if (sendEventCallback2) {
|
|
306
|
-
sendEventCallback2({
|
|
307
|
-
type: "ERROR",
|
|
308
|
-
errorMessage: `ErrorCode : 015, contact your admin or tech team`,
|
|
309
|
-
data: {
|
|
310
|
-
reason: `File not found in IndexedDB: ${value[i]}`,
|
|
311
|
-
fileId: value[i],
|
|
312
|
-
field: key
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
308
|
}
|
|
317
309
|
} else if (typeof value[i] === "object" && value[i] !== null) {
|
|
318
310
|
await traverse(value[i]);
|
|
@@ -327,14 +319,25 @@ async function processFileIds(data, sendEventCallback2) {
|
|
|
327
319
|
}
|
|
328
320
|
}
|
|
329
321
|
}
|
|
330
|
-
await traverse(
|
|
331
|
-
return
|
|
322
|
+
await traverse(clonedData);
|
|
323
|
+
return clonedData;
|
|
332
324
|
}
|
|
333
325
|
async function getFileFromIndexedDB2(fileId) {
|
|
334
326
|
return new Promise((resolve) => {
|
|
335
327
|
const request = indexedDB.open("Forms-Attachments", 3);
|
|
328
|
+
request.onupgradeneeded = (e) => {
|
|
329
|
+
const db = e.target.result;
|
|
330
|
+
if (!db.objectStoreNames.contains("Files")) {
|
|
331
|
+
db.createObjectStore("Files");
|
|
332
|
+
}
|
|
333
|
+
};
|
|
336
334
|
request.onsuccess = (event) => {
|
|
337
335
|
const db = event.target.result;
|
|
336
|
+
if (!db.objectStoreNames.contains("Files")) {
|
|
337
|
+
console.warn("Files store not found");
|
|
338
|
+
resolve(null);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
338
341
|
const store = db.transaction(["Files"], "readonly").objectStore("Files");
|
|
339
342
|
const getRequest = store.get(fileId);
|
|
340
343
|
getRequest.onsuccess = () => resolve(getRequest.result);
|
|
@@ -344,6 +347,473 @@ async function getFileFromIndexedDB2(fileId) {
|
|
|
344
347
|
});
|
|
345
348
|
}
|
|
346
349
|
|
|
350
|
+
// src/lib/dynamicValueProcessor.js
|
|
351
|
+
function processDynamicValues(formJson, appData) {
|
|
352
|
+
if (!formJson || !formJson.components) return null;
|
|
353
|
+
let dataMap = {};
|
|
354
|
+
const hasAppData = appData && (Array.isArray(appData) && appData.length > 0 || !Array.isArray(appData) && Object.keys(appData).length > 0);
|
|
355
|
+
if (hasAppData) {
|
|
356
|
+
if (Array.isArray(appData)) {
|
|
357
|
+
appData.forEach((item) => {
|
|
358
|
+
if (item.key) dataMap[item.key] = item.value;
|
|
359
|
+
});
|
|
360
|
+
} else {
|
|
361
|
+
dataMap = appData || {};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function processComponents(comps) {
|
|
365
|
+
if (!comps || !Array.isArray(comps)) return null;
|
|
366
|
+
for (const comp of comps) {
|
|
367
|
+
if (typeof comp.defaultValue === "string" && comp.defaultValue.trim().startsWith("{{") && comp.defaultValue.trim().endsWith("}}")) {
|
|
368
|
+
const key = comp.defaultValue.trim();
|
|
369
|
+
if (hasAppData && dataMap[key] !== void 0) {
|
|
370
|
+
comp.defaultValue = dataMap[key];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
let err;
|
|
374
|
+
if (comp.components) {
|
|
375
|
+
err = processComponents(comp.components);
|
|
376
|
+
if (err) return err;
|
|
377
|
+
}
|
|
378
|
+
if (comp.columns && Array.isArray(comp.columns)) {
|
|
379
|
+
for (const col of comp.columns) {
|
|
380
|
+
err = processComponents(col.components);
|
|
381
|
+
if (err) return err;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (comp.rows && Array.isArray(comp.rows)) {
|
|
385
|
+
for (const row of comp.rows) {
|
|
386
|
+
if (Array.isArray(row)) {
|
|
387
|
+
for (const cell of row) {
|
|
388
|
+
err = processComponents(cell.components);
|
|
389
|
+
if (err) return err;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return processComponents(formJson.components);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/lib/appDocuments.js
|
|
401
|
+
var DB_NAME = "AppDocuments";
|
|
402
|
+
var STORE_NAME = "documents";
|
|
403
|
+
var STORE_NAME_TYPO = "documnets";
|
|
404
|
+
function openDB(version) {
|
|
405
|
+
if (version) {
|
|
406
|
+
return new Promise((resolve, reject) => {
|
|
407
|
+
const request = indexedDB.open(DB_NAME, version);
|
|
408
|
+
request.onupgradeneeded = (event) => {
|
|
409
|
+
const db = event.target.result;
|
|
410
|
+
if (!db.objectStoreNames.contains(STORE_NAME) && !db.objectStoreNames.contains(STORE_NAME_TYPO)) {
|
|
411
|
+
db.createObjectStore(STORE_NAME, { keyPath: "id", autoIncrement: true });
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
request.onsuccess = (event) => resolve(event.target.result);
|
|
415
|
+
request.onerror = (event) => {
|
|
416
|
+
console.error("AppDocuments DB error:", event.target.error);
|
|
417
|
+
reject(event.target.error);
|
|
418
|
+
};
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
if (typeof window !== "undefined" && window.indexedDBUtils && window.indexedDBUtils.openDynamicDB) {
|
|
422
|
+
return window.indexedDBUtils.openDynamicDB(DB_NAME, STORE_NAME, STORE_NAME_TYPO);
|
|
423
|
+
}
|
|
424
|
+
return new Promise((resolve, reject) => {
|
|
425
|
+
const checkRequest = indexedDB.open(DB_NAME);
|
|
426
|
+
checkRequest.onupgradeneeded = (e) => {
|
|
427
|
+
const db = e.target.result;
|
|
428
|
+
if (!db.objectStoreNames.contains(STORE_NAME) && !db.objectStoreNames.contains(STORE_NAME_TYPO)) {
|
|
429
|
+
db.createObjectStore(STORE_NAME, { keyPath: "id", autoIncrement: true });
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
checkRequest.onsuccess = (e) => {
|
|
433
|
+
const db = e.target.result;
|
|
434
|
+
if (db.objectStoreNames.contains(STORE_NAME) || db.objectStoreNames.contains(STORE_NAME_TYPO)) {
|
|
435
|
+
resolve(db);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
const currentVersion = db.version;
|
|
439
|
+
const newVersion = currentVersion + 1;
|
|
440
|
+
db.close();
|
|
441
|
+
console.log(`[AppDocuments] Store missing. Upgrading from v${currentVersion} to v${newVersion}.`);
|
|
442
|
+
const upgradeRequest = indexedDB.open(DB_NAME, newVersion);
|
|
443
|
+
upgradeRequest.onupgradeneeded = (evt) => {
|
|
444
|
+
const upgradeDb = evt.target.result;
|
|
445
|
+
if (!upgradeDb.objectStoreNames.contains(STORE_NAME)) {
|
|
446
|
+
upgradeDb.createObjectStore(STORE_NAME, { keyPath: "id", autoIncrement: true });
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
upgradeRequest.onsuccess = (evt) => resolve(evt.target.result);
|
|
450
|
+
upgradeRequest.onerror = (evt) => {
|
|
451
|
+
console.error("[AppDocuments] DB Upgrade failed:", evt);
|
|
452
|
+
reject(evt);
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
checkRequest.onerror = (e) => {
|
|
456
|
+
console.error("[AppDocuments] DB Open failed:", e);
|
|
457
|
+
reject(e.target.error);
|
|
458
|
+
};
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
function getStoreName(db) {
|
|
462
|
+
if (db.objectStoreNames.contains(STORE_NAME)) return STORE_NAME;
|
|
463
|
+
if (db.objectStoreNames.contains(STORE_NAME_TYPO)) return STORE_NAME_TYPO;
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
async function hasDocuments() {
|
|
467
|
+
try {
|
|
468
|
+
const db = await openDB();
|
|
469
|
+
const actualStoreName = getStoreName(db);
|
|
470
|
+
if (!actualStoreName) {
|
|
471
|
+
console.warn(`AppDocuments DB found but no '${STORE_NAME}' or '${STORE_NAME_TYPO}' store exists.`);
|
|
472
|
+
db.close();
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
return new Promise((resolve) => {
|
|
476
|
+
const transaction = db.transaction([actualStoreName], "readonly");
|
|
477
|
+
const store = transaction.objectStore(actualStoreName);
|
|
478
|
+
const countRequest = store.count();
|
|
479
|
+
countRequest.onsuccess = () => {
|
|
480
|
+
console.log(`[AppDocuments] Count in ${actualStoreName}:`, countRequest.result);
|
|
481
|
+
db.close();
|
|
482
|
+
resolve(countRequest.result > 0);
|
|
483
|
+
};
|
|
484
|
+
countRequest.onerror = (e) => {
|
|
485
|
+
console.error("[AppDocuments] Error counting:", e);
|
|
486
|
+
db.close();
|
|
487
|
+
resolve(false);
|
|
488
|
+
};
|
|
489
|
+
});
|
|
490
|
+
} catch (e) {
|
|
491
|
+
console.error("[AppDocuments] Error checking documents:", e);
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
async function getAllDocuments() {
|
|
496
|
+
try {
|
|
497
|
+
const db = await openDB();
|
|
498
|
+
const actualStoreName = getStoreName(db);
|
|
499
|
+
if (!actualStoreName) {
|
|
500
|
+
db.close();
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
return new Promise((resolve) => {
|
|
504
|
+
const transaction = db.transaction([actualStoreName], "readonly");
|
|
505
|
+
const store = transaction.objectStore(actualStoreName);
|
|
506
|
+
const request = store.getAll();
|
|
507
|
+
request.onsuccess = () => {
|
|
508
|
+
db.close();
|
|
509
|
+
resolve(request.result);
|
|
510
|
+
};
|
|
511
|
+
request.onerror = () => {
|
|
512
|
+
db.close();
|
|
513
|
+
resolve([]);
|
|
514
|
+
};
|
|
515
|
+
});
|
|
516
|
+
} catch (e) {
|
|
517
|
+
console.error("Error getting documents:", e);
|
|
518
|
+
return [];
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
async function insertDocument(doc) {
|
|
522
|
+
try {
|
|
523
|
+
let db = await openDB();
|
|
524
|
+
let actualStoreName = getStoreName(db);
|
|
525
|
+
if (!actualStoreName) {
|
|
526
|
+
db.close();
|
|
527
|
+
throw new Error("Failed to open database with valid store.");
|
|
528
|
+
}
|
|
529
|
+
return new Promise((resolve, reject) => {
|
|
530
|
+
const transaction = db.transaction([actualStoreName], "readwrite");
|
|
531
|
+
const store = transaction.objectStore(actualStoreName);
|
|
532
|
+
const request = store.add(doc);
|
|
533
|
+
request.onsuccess = () => {
|
|
534
|
+
db.close();
|
|
535
|
+
resolve(request.result);
|
|
536
|
+
};
|
|
537
|
+
request.onerror = (e) => {
|
|
538
|
+
db.close();
|
|
539
|
+
reject(e.target.error);
|
|
540
|
+
};
|
|
541
|
+
});
|
|
542
|
+
} catch (e) {
|
|
543
|
+
console.error("Error inserting document:", e);
|
|
544
|
+
throw e;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async function deleteDocument(id) {
|
|
548
|
+
try {
|
|
549
|
+
const db = await openDB();
|
|
550
|
+
const actualStoreName = getStoreName(db);
|
|
551
|
+
if (!actualStoreName) {
|
|
552
|
+
db.close();
|
|
553
|
+
console.error("No valid document store found for deletion");
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
return new Promise((resolve, reject) => {
|
|
557
|
+
const transaction = db.transaction([actualStoreName], "readwrite");
|
|
558
|
+
const store = transaction.objectStore(actualStoreName);
|
|
559
|
+
const request = store.delete(id);
|
|
560
|
+
request.onsuccess = () => {
|
|
561
|
+
db.close();
|
|
562
|
+
resolve();
|
|
563
|
+
};
|
|
564
|
+
request.onerror = (e) => {
|
|
565
|
+
db.close();
|
|
566
|
+
reject(e.target.error);
|
|
567
|
+
};
|
|
568
|
+
});
|
|
569
|
+
} catch (e) {
|
|
570
|
+
console.error("Error deleting document:", e);
|
|
571
|
+
throw e;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// src/html-template/utils/openDocumentsModal.js
|
|
576
|
+
var DB_NAME2 = "AppDocuments";
|
|
577
|
+
var STORE_NAME2 = "documents";
|
|
578
|
+
var STORE_NAME_TYPO2 = "documnets";
|
|
579
|
+
function openDB2() {
|
|
580
|
+
return new Promise((resolve, reject) => {
|
|
581
|
+
const request = indexedDB.open(DB_NAME2);
|
|
582
|
+
request.onsuccess = (event) => resolve(event.target.result);
|
|
583
|
+
request.onerror = (event) => reject(event.target.error);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
function getStoreName2(db) {
|
|
587
|
+
if (db.objectStoreNames.contains(STORE_NAME2)) return STORE_NAME2;
|
|
588
|
+
if (db.objectStoreNames.contains(STORE_NAME_TYPO2)) return STORE_NAME_TYPO2;
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
async function getAllDocuments2() {
|
|
592
|
+
try {
|
|
593
|
+
const db = await openDB2();
|
|
594
|
+
const actualStoreName = getStoreName2(db);
|
|
595
|
+
if (!actualStoreName) {
|
|
596
|
+
db.close();
|
|
597
|
+
return [];
|
|
598
|
+
}
|
|
599
|
+
return new Promise((resolve) => {
|
|
600
|
+
const transaction = db.transaction([actualStoreName], "readonly");
|
|
601
|
+
const store = transaction.objectStore(actualStoreName);
|
|
602
|
+
const request = store.getAll();
|
|
603
|
+
request.onsuccess = () => {
|
|
604
|
+
db.close();
|
|
605
|
+
resolve(request.result);
|
|
606
|
+
};
|
|
607
|
+
request.onerror = () => {
|
|
608
|
+
db.close();
|
|
609
|
+
resolve([]);
|
|
610
|
+
};
|
|
611
|
+
});
|
|
612
|
+
} catch (e) {
|
|
613
|
+
console.warn("Error reading AppDocuments DB:", e);
|
|
614
|
+
return [];
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
async function openDocumentsModal() {
|
|
618
|
+
if (typeof window.showDynamicModal !== "function") {
|
|
619
|
+
console.error("showDynamicModal is not defined.");
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
window.showDynamicModal("App Documents", [], `
|
|
623
|
+
<div style="text-align: center; padding: 40px;">
|
|
624
|
+
<i class="fa fa-spinner fa-spin" style="font-size: 30px; color: #2185d0;"></i>
|
|
625
|
+
<div style="margin-top: 15px; color: #666; font-size: 16px;">Loading documents...</div>
|
|
626
|
+
</div>
|
|
627
|
+
`);
|
|
628
|
+
try {
|
|
629
|
+
const docs = await getAllDocuments2();
|
|
630
|
+
let bodyContent = "";
|
|
631
|
+
if (docs && docs.length > 0) {
|
|
632
|
+
bodyContent = `<div class="ui middle aligned divided list" style="width:100%;margin:0;">`;
|
|
633
|
+
docs.forEach((doc) => {
|
|
634
|
+
const name = doc.name || doc.title || "Untitled Document";
|
|
635
|
+
const desc = doc.description || "";
|
|
636
|
+
let metaInfo = "";
|
|
637
|
+
let iconClass = "file outline";
|
|
638
|
+
if (doc.type) {
|
|
639
|
+
if (doc.type.includes("pdf")) iconClass = "file pdf outline red";
|
|
640
|
+
else if (doc.type.includes("image")) iconClass = "file image outline blue";
|
|
641
|
+
else if (doc.type.includes("text")) iconClass = "file text outline grey";
|
|
642
|
+
}
|
|
643
|
+
if (Number.isInteger(doc.id)) {
|
|
644
|
+
metaInfo = new Date(doc.id).toLocaleDateString();
|
|
645
|
+
}
|
|
646
|
+
bodyContent += `
|
|
647
|
+
<div class="item" style="padding:12px 10px;display:flex;align-items:center;">
|
|
648
|
+
<i class="${iconClass} icon large" style="margin-right:15px;"></i>
|
|
649
|
+
|
|
650
|
+
<div class="content" style="flex:1;min-width:0;">
|
|
651
|
+
<div class="header" style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
|
|
652
|
+
${name}
|
|
653
|
+
</div>
|
|
654
|
+
${desc ? `<div class="description" style="font-size:12px;color:#666;">${desc}</div>` : ""}
|
|
655
|
+
${metaInfo ? `<div class="meta" style="font-size:11px;color:#999;">${metaInfo}</div>` : ""}
|
|
656
|
+
</div>
|
|
657
|
+
|
|
658
|
+
<button class="ui button mini basic primary"
|
|
659
|
+
onclick="window.downloadDocument(${doc.id})">
|
|
660
|
+
<i class="download icon"></i> Download
|
|
661
|
+
</button>
|
|
662
|
+
</div>`;
|
|
663
|
+
});
|
|
664
|
+
bodyContent += `</div>`;
|
|
665
|
+
} else {
|
|
666
|
+
bodyContent = `
|
|
667
|
+
<div style="text-align:center;padding:50px;color:#999;">
|
|
668
|
+
<i class="folder open outline icon" style="font-size:40px;"></i>
|
|
669
|
+
<div>No documents available</div>
|
|
670
|
+
</div>`;
|
|
671
|
+
}
|
|
672
|
+
window.showDynamicModal(
|
|
673
|
+
"App Documents",
|
|
674
|
+
[{ label: "Close", callback: () => {
|
|
675
|
+
}, className: "ui button" }],
|
|
676
|
+
bodyContent
|
|
677
|
+
);
|
|
678
|
+
if (!window.downloadDocument) {
|
|
679
|
+
window.downloadDocument = async function(id) {
|
|
680
|
+
const all = await getAllDocuments2();
|
|
681
|
+
const found = all.find((d) => d.id == id);
|
|
682
|
+
if (!found) {
|
|
683
|
+
console.log("\u274C Document not found.");
|
|
684
|
+
if (window.sendEventCallback) {
|
|
685
|
+
window.sendEventCallback({
|
|
686
|
+
type: "ERROR",
|
|
687
|
+
errorMessage: "ErrorCode : 017, Document not found",
|
|
688
|
+
data: { reason: "Document not found", technicalError: null }
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
console.log("Downloading:", found);
|
|
694
|
+
let incomingData = found.url || found.data || found.file && found.file.data;
|
|
695
|
+
let downloadUrl = null;
|
|
696
|
+
if (incomingData && incomingData.startsWith("data:")) {
|
|
697
|
+
const comma = incomingData.indexOf(",");
|
|
698
|
+
if (comma === -1) {
|
|
699
|
+
console.log("\u274C Invalid file format.");
|
|
700
|
+
if (window.sendEventCallback) {
|
|
701
|
+
window.sendEventCallback({
|
|
702
|
+
type: "ERROR",
|
|
703
|
+
errorMessage: "ErrorCode : 018, Invalid file format",
|
|
704
|
+
data: { reason: "Invalid file format", technicalError: null }
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
const header = incomingData.substring(0, comma);
|
|
710
|
+
let base64 = incomingData.substring(comma + 1);
|
|
711
|
+
const mimeMatch = header.match(/:(.*?);/);
|
|
712
|
+
const mime = mimeMatch ? mimeMatch[1] : "application/octet-stream";
|
|
713
|
+
base64 = base64.replace(/\s/g, "");
|
|
714
|
+
if (!/^[A-Za-z0-9+/=]+$/.test(base64)) {
|
|
715
|
+
console.error("Invalid base64:", base64.slice(0, 50));
|
|
716
|
+
console.log("\u274C File is corrupted (invalid base64).");
|
|
717
|
+
if (window.sendEventCallback) {
|
|
718
|
+
window.sendEventCallback({
|
|
719
|
+
type: "ERROR",
|
|
720
|
+
errorMessage: "ErrorCode : 019, File is corrupted (invalid base64)",
|
|
721
|
+
data: { reason: "File is corrupted (invalid base64)", technicalError: null }
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
try {
|
|
727
|
+
const binary = atob(base64);
|
|
728
|
+
const bytes = new Uint8Array(binary.length);
|
|
729
|
+
for (let i = 0; i < binary.length; i++) {
|
|
730
|
+
bytes[i] = binary.charCodeAt(i);
|
|
731
|
+
}
|
|
732
|
+
const blob = new Blob([bytes], { type: mime });
|
|
733
|
+
if (!blob.size) {
|
|
734
|
+
console.log("\u274C File is empty.");
|
|
735
|
+
if (window.sendEventCallback) {
|
|
736
|
+
window.sendEventCallback({
|
|
737
|
+
type: "ERROR",
|
|
738
|
+
errorMessage: "ErrorCode : 020, File is empty",
|
|
739
|
+
data: { reason: "File is empty", technicalError: null }
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
downloadUrl = URL.createObjectURL(blob);
|
|
745
|
+
} catch (err) {
|
|
746
|
+
console.error("Base64 decode failed:", err);
|
|
747
|
+
if (err.name === "InvalidCharacterError") {
|
|
748
|
+
console.log("\u274C File is corrupted (invalid encoding).");
|
|
749
|
+
if (window.sendEventCallback) {
|
|
750
|
+
window.sendEventCallback({
|
|
751
|
+
type: "ERROR",
|
|
752
|
+
errorMessage: "ErrorCode : 021, File is corrupted (invalid encoding)",
|
|
753
|
+
data: { reason: "File is corrupted (invalid encoding)", technicalError: err }
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
} else {
|
|
757
|
+
console.log("\u274C Failed to process file.");
|
|
758
|
+
if (window.sendEventCallback) {
|
|
759
|
+
window.sendEventCallback({
|
|
760
|
+
type: "ERROR",
|
|
761
|
+
errorMessage: "ErrorCode : 022, Failed to process file",
|
|
762
|
+
data: { reason: "Failed to process file", technicalError: err }
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
} else if (found.file instanceof Blob) {
|
|
769
|
+
if (!found.file.size) {
|
|
770
|
+
console.log("\u274C File is empty.");
|
|
771
|
+
if (window.sendEventCallback) {
|
|
772
|
+
window.sendEventCallback({
|
|
773
|
+
type: "ERROR",
|
|
774
|
+
errorMessage: "ErrorCode : 023, File is empty",
|
|
775
|
+
data: { reason: "File is empty", technicalError: null }
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
downloadUrl = URL.createObjectURL(found.file);
|
|
781
|
+
} else {
|
|
782
|
+
console.log("\u274C No downloadable content found.");
|
|
783
|
+
if (window.sendEventCallback) {
|
|
784
|
+
window.sendEventCallback({
|
|
785
|
+
type: "ERROR",
|
|
786
|
+
errorMessage: "ErrorCode : 024, No downloadable content found",
|
|
787
|
+
data: { reason: "No downloadable content found", technicalError: null }
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const a = document.createElement("a");
|
|
793
|
+
a.href = downloadUrl;
|
|
794
|
+
a.download = found.name || "document";
|
|
795
|
+
document.body.appendChild(a);
|
|
796
|
+
a.click();
|
|
797
|
+
setTimeout(() => {
|
|
798
|
+
URL.revokeObjectURL(downloadUrl);
|
|
799
|
+
a.remove();
|
|
800
|
+
}, 1e4);
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
} catch (err) {
|
|
804
|
+
console.error("Load failed", err);
|
|
805
|
+
console.log("\u274C Failed to load documents.");
|
|
806
|
+
if (window.sendEventCallback) {
|
|
807
|
+
window.sendEventCallback({
|
|
808
|
+
type: "ERROR",
|
|
809
|
+
errorMessage: "ErrorCode : 025, Failed to load documents",
|
|
810
|
+
data: { reason: "Failed to load documents", technicalError: err }
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
window.openDocumentsModal = openDocumentsModal;
|
|
816
|
+
|
|
347
817
|
// src/__temp_build.js
|
|
348
818
|
async function loadUnviredForms({
|
|
349
819
|
formsData = "formIOComponent",
|
|
@@ -353,33 +823,37 @@ async function loadUnviredForms({
|
|
|
353
823
|
options = {
|
|
354
824
|
nestedFormData: [{}],
|
|
355
825
|
masterData: [{}],
|
|
356
|
-
title: "the form title entered",
|
|
357
|
-
descrciption: "the form description entered",
|
|
358
826
|
mode: "",
|
|
359
|
-
privateExternal: "",
|
|
360
|
-
permission: "",
|
|
361
827
|
platform: "",
|
|
828
|
+
permission: "",
|
|
362
829
|
language: "",
|
|
830
|
+
privateExternal: "",
|
|
831
|
+
title: "the form title entered",
|
|
832
|
+
descrciption: "the form description entered",
|
|
363
833
|
translations: {},
|
|
364
|
-
environmentVariable: [],
|
|
365
834
|
themeData: {},
|
|
366
835
|
userData: {},
|
|
367
|
-
appData: {},
|
|
368
836
|
controlData: {},
|
|
369
|
-
showBackButton: false,
|
|
370
|
-
showMoreButton: true,
|
|
371
837
|
commentsData: [],
|
|
372
838
|
vobArr: [],
|
|
839
|
+
appData: [],
|
|
840
|
+
environmentVariable: [],
|
|
373
841
|
formioLibPath: {
|
|
374
842
|
formioPath: "assets/formio.full.min.js"
|
|
375
843
|
},
|
|
376
|
-
|
|
844
|
+
showComments: false,
|
|
845
|
+
showHelp: false,
|
|
846
|
+
showBackButton: false,
|
|
847
|
+
showLoader: true,
|
|
848
|
+
showMoreButton: true,
|
|
849
|
+
showCompleteAlways: false,
|
|
850
|
+
requireCompleteForm: true
|
|
377
851
|
}
|
|
378
852
|
}) {
|
|
379
853
|
var _a, _b;
|
|
380
854
|
let fileKeys = [];
|
|
381
855
|
let formJson;
|
|
382
|
-
console.log("
|
|
856
|
+
console.log("data recive step 1", formsData, submissionData, options);
|
|
383
857
|
function sendEventCallback2(params) {
|
|
384
858
|
const eventStructure = sendEventCallback(params);
|
|
385
859
|
if (typeof eventCallback === "function") {
|
|
@@ -396,6 +870,7 @@ async function loadUnviredForms({
|
|
|
396
870
|
});
|
|
397
871
|
return;
|
|
398
872
|
}
|
|
873
|
+
processDynamicValues(formJson, options.appData);
|
|
399
874
|
const template = formJson;
|
|
400
875
|
const nestedFormArrTemp = options.nestedFormData || [];
|
|
401
876
|
const masterDataArrTemp = options.masterData || [];
|
|
@@ -433,13 +908,17 @@ async function loadUnviredForms({
|
|
|
433
908
|
"masterdata"
|
|
434
909
|
);
|
|
435
910
|
if (submissionData && template) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
911
|
+
try {
|
|
912
|
+
const r = await validateAttachments(
|
|
913
|
+
mergedWithMasterData,
|
|
914
|
+
submissionData,
|
|
915
|
+
sendEventCallback2
|
|
916
|
+
);
|
|
917
|
+
fileKeys = r.fileKeys;
|
|
918
|
+
if (r.missingFiles.length > 0) {
|
|
919
|
+
}
|
|
920
|
+
} catch (error) {
|
|
921
|
+
console.warn("Attachment validation skipped:", error);
|
|
443
922
|
}
|
|
444
923
|
}
|
|
445
924
|
if ((options == null ? void 0 : options.appData) && ((_a = Object.keys(options == null ? void 0 : options.appData)) == null ? void 0 : _a.length) > 0) {
|
|
@@ -1158,6 +1637,14 @@ body {
|
|
|
1158
1637
|
/* subtle shadow for elevation */
|
|
1159
1638
|
}
|
|
1160
1639
|
|
|
1640
|
+
|
|
1641
|
+
#submitBtn,
|
|
1642
|
+
#saveBtn {
|
|
1643
|
+
width: 110px;
|
|
1644
|
+
display: flex;
|
|
1645
|
+
justify-content: space-evenly;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1161
1648
|
.form-cmt-btn {
|
|
1162
1649
|
width: 40px;
|
|
1163
1650
|
height: 40px;
|
|
@@ -1193,8 +1680,9 @@ body {
|
|
|
1193
1680
|
width: 100%;
|
|
1194
1681
|
background-color: #ffffff;
|
|
1195
1682
|
padding: 6px;
|
|
1196
|
-
justify-content:
|
|
1683
|
+
justify-content: flex-end;
|
|
1197
1684
|
align-items: center;
|
|
1685
|
+
gap: 8px;
|
|
1198
1686
|
border-top: 1px solid #ddd;
|
|
1199
1687
|
z-index: 1000;
|
|
1200
1688
|
box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.05);
|
|
@@ -1206,18 +1694,20 @@ body {
|
|
|
1206
1694
|
display: none;
|
|
1207
1695
|
position: absolute;
|
|
1208
1696
|
bottom: 100%;
|
|
1209
|
-
left:
|
|
1210
|
-
margin-bottom:
|
|
1697
|
+
left: -170px;
|
|
1698
|
+
margin-bottom: 16px;
|
|
1211
1699
|
background-color: #fff;
|
|
1212
1700
|
border: 1px solid #ddd;
|
|
1213
1701
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
1214
1702
|
padding: 6px;
|
|
1215
1703
|
border-radius: 6px;
|
|
1216
|
-
z-index:
|
|
1704
|
+
z-index: 1000;
|
|
1217
1705
|
flex-direction: column;
|
|
1218
1706
|
gap: 0px;
|
|
1219
1707
|
}
|
|
1220
1708
|
|
|
1709
|
+
#unvired-more-btn {}
|
|
1710
|
+
|
|
1221
1711
|
/* Print and PDF Modes */
|
|
1222
1712
|
@media print {
|
|
1223
1713
|
|
|
@@ -1429,7 +1919,6 @@ body {
|
|
|
1429
1919
|
|
|
1430
1920
|
@keyframes sdk-pulse {
|
|
1431
1921
|
|
|
1432
|
-
0%,
|
|
1433
1922
|
100% {
|
|
1434
1923
|
opacity: 1;
|
|
1435
1924
|
}
|
|
@@ -1439,6 +1928,48 @@ body {
|
|
|
1439
1928
|
}
|
|
1440
1929
|
}
|
|
1441
1930
|
|
|
1931
|
+
/* Responsive Footer for Mobile */
|
|
1932
|
+
@media (max-width: 600px) {
|
|
1933
|
+
#sticky-footer {
|
|
1934
|
+
justify-content: flex-end;
|
|
1935
|
+
padding: 4px;
|
|
1936
|
+
gap: 4px;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
#submitBtn {
|
|
1940
|
+
|
|
1941
|
+
width: 105px;
|
|
1942
|
+
min-width: 108px;
|
|
1943
|
+
flex-grow: 0;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
|
|
1947
|
+
#saveBtn {
|
|
1948
|
+
width: 80px;
|
|
1949
|
+
min-width: 90px;
|
|
1950
|
+
flex-grow: 0;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
#unvired-more-btn {
|
|
1954
|
+
margin-left: 10px;
|
|
1955
|
+
margin-right: 10px;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
/* Fix tooltip on mobile to prevent cutoff */
|
|
1959
|
+
#moreTooltip {
|
|
1960
|
+
position: fixed;
|
|
1961
|
+
bottom: 70px;
|
|
1962
|
+
left: 20px;
|
|
1963
|
+
right: 20px;
|
|
1964
|
+
width: auto;
|
|
1965
|
+
margin-bottom: 0;
|
|
1966
|
+
max-width: 300px;
|
|
1967
|
+
margin-left: auto;
|
|
1968
|
+
margin-right: auto;
|
|
1969
|
+
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1442
1973
|
/* === STYLE_SEPARATOR === */
|
|
1443
1974
|
|
|
1444
1975
|
.r6o-drawing{cursor:none}.r6o-relations-layer.readonly .handle rect{pointer-events:none}.r6o-relations-layer{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.r6o-relations-layer circle{stroke:#515151;stroke-width:.4;fill:#3f3f3f}.r6o-relations-layer path{stroke:#595959;stroke-linecap:round;stroke-linejoin:round;fill:transparent}.r6o-relations-layer path.connection{stroke-width:1.6;stroke-dasharray:2,3}.r6o-relations-layer path.r6o-arrow{stroke-width:1.8;fill:#7f7f7f}.r6o-relations-layer .handle rect{stroke-width:1;stroke:#595959;fill:#fff;pointer-events:auto;cursor:pointer}.r6o-relations-layer .handle text{font-size:10px}.r6o-relations-layer .hover{stroke:rgba(63,63,63,.9);stroke-width:1.4;fill:transparent}
|
|
@@ -27129,7 +27660,9 @@ select.ui.dropdown {
|
|
|
27129
27660
|
/* -----------------
|
|
27130
27661
|
Floating label end
|
|
27131
27662
|
-------------------- */
|
|
27132
|
-
`.split(
|
|
27663
|
+
`.split(
|
|
27664
|
+
"\n\n/* === STYLE_SEPARATOR === */\n\n"
|
|
27665
|
+
);
|
|
27133
27666
|
cssContents.forEach((cssContent, index) => {
|
|
27134
27667
|
if (cssContent.trim()) {
|
|
27135
27668
|
const styleElement = document.createElement("style");
|
|
@@ -27201,6 +27734,34 @@ select.ui.dropdown {
|
|
|
27201
27734
|
0%, 100% { opacity: 1; }
|
|
27202
27735
|
50% { opacity: 0.5; }
|
|
27203
27736
|
}
|
|
27737
|
+
.sdk-loader-back-btn {
|
|
27738
|
+
position: absolute;
|
|
27739
|
+
top: 20px;
|
|
27740
|
+
left: 20px;
|
|
27741
|
+
background: transparent;
|
|
27742
|
+
border: none;
|
|
27743
|
+
color: #333;
|
|
27744
|
+
font-size: 1.2rem;
|
|
27745
|
+
cursor: pointer;
|
|
27746
|
+
padding: 10px;
|
|
27747
|
+
border-radius: 50%;
|
|
27748
|
+
transition: background 0.2s ease;
|
|
27749
|
+
pointer-events: auto;
|
|
27750
|
+
display: flex;
|
|
27751
|
+
align-items: center;
|
|
27752
|
+
justify-content: center;
|
|
27753
|
+
margin: 0;
|
|
27754
|
+
width: 40px;
|
|
27755
|
+
height: 40px;
|
|
27756
|
+
}
|
|
27757
|
+
.sdk-loader-back-btn:hover {
|
|
27758
|
+
background: rgba(0, 0, 0, 0.05);
|
|
27759
|
+
color: #000;
|
|
27760
|
+
border: none;
|
|
27761
|
+
}
|
|
27762
|
+
.sdk-loader-back-btn i {
|
|
27763
|
+
margin: 0;
|
|
27764
|
+
}
|
|
27204
27765
|
`;
|
|
27205
27766
|
document.head.appendChild(additionalStyle);
|
|
27206
27767
|
}
|
|
@@ -27229,24 +27790,52 @@ select.ui.dropdown {
|
|
|
27229
27790
|
<div id="formio-cmt" style="margin-bottom: 20px;"></div>
|
|
27230
27791
|
</div>
|
|
27231
27792
|
<div id="sticky-footer">
|
|
27793
|
+
<button class="ui button primary dataGrid-addRow" id="saveBtn" disabled="true" onclick="FormOnSave()">
|
|
27794
|
+
<i class="icon save large"></i>Save
|
|
27795
|
+
</button>
|
|
27796
|
+
<button class="ui button primary dataGrid-addRow" id="submitBtn" style="display:none" onclick="FormOnSubmit()">
|
|
27797
|
+
<i class="icon save large"></i>Submit
|
|
27798
|
+
</button>
|
|
27799
|
+
|
|
27800
|
+
<!-- Quick Action Buttons -->
|
|
27801
|
+
<div id="quick-actions" style="display: flex; align-items: center;">
|
|
27802
|
+
<i id="quickCompleteBtn" class="icon clipboard check large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="FormOnSubmit()" title="Complete"></i>
|
|
27803
|
+
<i id="quickSaveBtn" class="icon save large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="FormOnSave()" title="Save"></i>
|
|
27804
|
+
<i id="quickDocumentsBtn" class="icon file alternate large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="openDocumentsModal()" title="Documents"></i>
|
|
27805
|
+
<i id="quickCommentsBtn" class="icon comment large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="loadComments()" title="Comments"></i>
|
|
27806
|
+
<i id="quickHelpBtn" class="icon question circle large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="openHelpLink()" title="Help"></i>
|
|
27807
|
+
</div>
|
|
27808
|
+
|
|
27232
27809
|
<div class="relative-position">
|
|
27233
|
-
|
|
27234
|
-
|
|
27810
|
+
<button class="ui button primary " id="unvired-more-btn" onclick="toggleTooltip(event)">
|
|
27811
|
+
<i class="icon bars large" style="margin: 0;"></i>
|
|
27235
27812
|
</button>
|
|
27236
27813
|
<div id="moreTooltip" style="display: none;" class="ui vertical menu">
|
|
27237
|
-
<div class="item">
|
|
27238
|
-
<div class="divider"
|
|
27814
|
+
<div class="item" id="completeOption" onclick="FormOnSubmit()" style="display: none;">Complete</div>
|
|
27815
|
+
<div class="divider"></div>
|
|
27816
|
+
<div class="item" id="saveOption" onclick="FormOnSave()" style="display: none;">Save</div>
|
|
27817
|
+
<div class="divider"></div>
|
|
27818
|
+
<div class="item" id="documentsOption" onclick="openDocumentsModal()" style="display: none;">Documents</div>
|
|
27819
|
+
<div class="divider"></div>
|
|
27239
27820
|
<div class="item" id="comments-item" style="display: none;" onclick="loadComments()">Comments</div>
|
|
27240
27821
|
<div class="divider"></div>
|
|
27241
|
-
<div class="item" onclick="openHelpLink()">Help</div>
|
|
27822
|
+
<div class="item" id="help-item" style="display: none;" onclick="openHelpLink()">Help</div>
|
|
27242
27823
|
</div>
|
|
27243
27824
|
</div>
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
<
|
|
27248
|
-
|
|
27249
|
-
</
|
|
27825
|
+
</div>
|
|
27826
|
+
<div class="ui modal" id="documentsModal">
|
|
27827
|
+
<i class="close icon"></i>
|
|
27828
|
+
<div class="header">
|
|
27829
|
+
App Documents
|
|
27830
|
+
</div>
|
|
27831
|
+
<div class="content">
|
|
27832
|
+
<div class="ui relaxed divided list" id="documentsList">
|
|
27833
|
+
<div class="item">Loading...</div>
|
|
27834
|
+
</div>
|
|
27835
|
+
</div>
|
|
27836
|
+
<div class="actions">
|
|
27837
|
+
<div class="ui button" onclick="closeDocumentsModal()">Close</div>
|
|
27838
|
+
</div>
|
|
27250
27839
|
</div>
|
|
27251
27840
|
`;
|
|
27252
27841
|
let loaderElement = null;
|
|
@@ -27257,23 +27846,48 @@ select.ui.dropdown {
|
|
|
27257
27846
|
<div class="sdk-loader-spinner"></div>
|
|
27258
27847
|
<div class="sdk-loader-text">Loading Form...</div>
|
|
27259
27848
|
<div class="sdk-loader-subtext">Please wait while we prepare your form</div>
|
|
27849
|
+
<button class="form-back-btn sdk-loader-back-btn" onclick="FormOnBackLoading()">
|
|
27850
|
+
<i class="icon arrow left"></i>
|
|
27851
|
+
</button>
|
|
27260
27852
|
`;
|
|
27261
27853
|
container.appendChild(loaderElement);
|
|
27262
27854
|
}
|
|
27263
|
-
window.toggleTooltip = function() {
|
|
27855
|
+
window.toggleTooltip = function(event) {
|
|
27856
|
+
if (event) {
|
|
27857
|
+
event.stopPropagation();
|
|
27858
|
+
}
|
|
27264
27859
|
const tooltip = document.getElementById("moreTooltip");
|
|
27265
|
-
const commentsDivider = document.getElementById("comments-divider");
|
|
27266
27860
|
const commentsItem = document.getElementById("comments-item");
|
|
27861
|
+
const helpItem = document.getElementById("help-item");
|
|
27862
|
+
if (options.showHelp) {
|
|
27863
|
+
helpItem.style.display = "block";
|
|
27864
|
+
} else {
|
|
27865
|
+
helpItem.style.display = "none";
|
|
27866
|
+
}
|
|
27867
|
+
if (options.showComments) {
|
|
27868
|
+
commentsItem.style.display = "block";
|
|
27869
|
+
} else {
|
|
27870
|
+
commentsItem.style.display = "none";
|
|
27871
|
+
}
|
|
27267
27872
|
if (tooltip.style.display === "none") {
|
|
27268
27873
|
tooltip.style.display = "flex";
|
|
27269
|
-
|
|
27270
|
-
commentsDivider.style.display = "";
|
|
27271
|
-
commentsItem.style.display = "";
|
|
27272
|
-
}, 500);
|
|
27874
|
+
tooltip.style.flexDirection = "column";
|
|
27273
27875
|
} else {
|
|
27274
27876
|
tooltip.style.display = "none";
|
|
27275
|
-
|
|
27276
|
-
|
|
27877
|
+
return;
|
|
27878
|
+
}
|
|
27879
|
+
const items = Array.from(tooltip.querySelectorAll(".item"));
|
|
27880
|
+
const dividers = Array.from(tooltip.querySelectorAll(".divider"));
|
|
27881
|
+
dividers.forEach((d) => d.style.display = "none");
|
|
27882
|
+
const visibleItems = items.filter((item) => {
|
|
27883
|
+
return item.style.display !== "none" && item.offsetParent !== null;
|
|
27884
|
+
}).filter((item) => item.style.display !== "none");
|
|
27885
|
+
for (let i = 0; i < visibleItems.length - 1; i++) {
|
|
27886
|
+
const item = visibleItems[i];
|
|
27887
|
+
let next = item.nextElementSibling;
|
|
27888
|
+
if (next && next.classList.contains("divider")) {
|
|
27889
|
+
next.style.display = "block";
|
|
27890
|
+
}
|
|
27277
27891
|
}
|
|
27278
27892
|
};
|
|
27279
27893
|
window.openHelpLink = function() {
|
|
@@ -27288,36 +27902,46 @@ select.ui.dropdown {
|
|
|
27288
27902
|
}
|
|
27289
27903
|
};
|
|
27290
27904
|
document.addEventListener("click", function(event) {
|
|
27291
|
-
const moreBtn2 = document.getElementById("
|
|
27905
|
+
const moreBtn2 = document.getElementById("unvired-more-btn");
|
|
27292
27906
|
const tooltip = document.getElementById("moreTooltip");
|
|
27293
27907
|
if (moreBtn2 && tooltip && !moreBtn2.contains(event.target) && !tooltip.contains(event.target)) {
|
|
27294
27908
|
tooltip.style.display = "none";
|
|
27295
27909
|
}
|
|
27296
27910
|
});
|
|
27297
|
-
window.loadComments = function() {
|
|
27911
|
+
window.loadComments = window.loadComments || function() {
|
|
27298
27912
|
if (typeof window.loadCommentsFunction === "function") {
|
|
27299
27913
|
window.loadCommentsFunction();
|
|
27300
27914
|
}
|
|
27301
27915
|
};
|
|
27302
|
-
window.FormOnBack = function() {
|
|
27916
|
+
window.FormOnBack = window.FormOnBack || function() {
|
|
27303
27917
|
sendEventCallback2({ type: "FORM_BACK_NAVIGATION" });
|
|
27304
27918
|
};
|
|
27305
|
-
window.
|
|
27919
|
+
window.FormOnBackLoading = window.FormOnBackLoading || function() {
|
|
27920
|
+
console.log("Back button clicked during loading, canceling form load");
|
|
27921
|
+
if (loaderElement) {
|
|
27922
|
+
loaderElement.classList.add("hidden");
|
|
27923
|
+
if (loaderElement.parentNode) {
|
|
27924
|
+
loaderElement.parentNode.removeChild(loaderElement);
|
|
27925
|
+
}
|
|
27926
|
+
}
|
|
27927
|
+
sendEventCallback2({ type: "FORM_BACK_NAVIGATION" });
|
|
27928
|
+
};
|
|
27929
|
+
window.CommentOnBack = window.CommentOnBack || function() {
|
|
27306
27930
|
if (typeof window.commentOnBackFunction === "function") {
|
|
27307
27931
|
window.commentOnBackFunction();
|
|
27308
27932
|
}
|
|
27309
27933
|
};
|
|
27310
|
-
window.submitComments = function() {
|
|
27934
|
+
window.submitComments = window.submitComments || function() {
|
|
27311
27935
|
if (typeof window.submitCommentsFunction === "function") {
|
|
27312
27936
|
window.submitCommentsFunction();
|
|
27313
27937
|
}
|
|
27314
27938
|
};
|
|
27315
|
-
window.FormOnSave = function() {
|
|
27939
|
+
window.FormOnSave = window.FormOnSave || function() {
|
|
27316
27940
|
if (typeof window.formOnSaveFunction === "function") {
|
|
27317
27941
|
window.formOnSaveFunction();
|
|
27318
27942
|
}
|
|
27319
27943
|
};
|
|
27320
|
-
window.FormOnSubmit = function() {
|
|
27944
|
+
window.FormOnSubmit = window.FormOnSubmit || function() {
|
|
27321
27945
|
if (typeof window.formOnSubmitFunction === "function") {
|
|
27322
27946
|
window.formOnSubmitFunction();
|
|
27323
27947
|
}
|
|
@@ -48239,6 +48863,14 @@ async function startCameraScanner() {
|
|
|
48239
48863
|
|
|
48240
48864
|
showBarcodeError(errorMessage);
|
|
48241
48865
|
setTimeout(() => closeScannerModal(), 3000);
|
|
48866
|
+
|
|
48867
|
+
if (window.sendEventCallback) {
|
|
48868
|
+
window.sendEventCallback({
|
|
48869
|
+
type: "ERROR",
|
|
48870
|
+
errorMessage: "ErrorCode : 012, Camera access error",
|
|
48871
|
+
data: { technicalError: err, reason: errorMessage }
|
|
48872
|
+
});
|
|
48873
|
+
}
|
|
48242
48874
|
}
|
|
48243
48875
|
}
|
|
48244
48876
|
|
|
@@ -48622,7 +49254,7 @@ function injectBarcodeModalStyles() {
|
|
|
48622
49254
|
|
|
48623
49255
|
(function(){
|
|
48624
49256
|
// Listen for "getLocation" custom event
|
|
48625
|
-
|
|
49257
|
+
document.addEventListener("getLocation", function (event) {
|
|
48626
49258
|
const { compObj, controlId } = event.detail;
|
|
48627
49259
|
window.compId = controlId;
|
|
48628
49260
|
getLocationFromBrowser(controlId); // Pass controlId to getLocationFromBrowser
|
|
@@ -48632,7 +49264,7 @@ function injectBarcodeModalStyles() {
|
|
|
48632
49264
|
function getLocationFromBrowser(componentID) {
|
|
48633
49265
|
// Check if running in Cordova environment
|
|
48634
49266
|
const isCordova = !!(window.cordova || window.PhoneGap || window.phonegap);
|
|
48635
|
-
|
|
49267
|
+
|
|
48636
49268
|
if (!navigator.geolocation) {
|
|
48637
49269
|
showLocationError("Geolocation is not supported by this device.");
|
|
48638
49270
|
return;
|
|
@@ -48653,7 +49285,7 @@ function getLocationFromBrowser(componentID) {
|
|
|
48653
49285
|
showLocationError("Location permission was denied. Please enable it in browser settings and refresh the page.");
|
|
48654
49286
|
return;
|
|
48655
49287
|
}
|
|
48656
|
-
|
|
49288
|
+
|
|
48657
49289
|
if (permissionStatus.state === "granted" || permissionStatus.state === "prompt") {
|
|
48658
49290
|
requestLocation(componentID);
|
|
48659
49291
|
}
|
|
@@ -48671,7 +49303,7 @@ function getLocationFromBrowser(componentID) {
|
|
|
48671
49303
|
|
|
48672
49304
|
function requestLocation(componentID) {
|
|
48673
49305
|
const isCordova = !!(window.cordova || window.PhoneGap || window.phonegap);
|
|
48674
|
-
|
|
49306
|
+
|
|
48675
49307
|
const options = {
|
|
48676
49308
|
enableHighAccuracy: true,
|
|
48677
49309
|
timeout: isCordova ? 30000 : 10000, // Longer timeout for Cordova
|
|
@@ -48688,7 +49320,7 @@ function requestLocation(componentID) {
|
|
|
48688
49320
|
},
|
|
48689
49321
|
});
|
|
48690
49322
|
document.dispatchEvent(customEvent);
|
|
48691
|
-
|
|
49323
|
+
|
|
48692
49324
|
// Send success event
|
|
48693
49325
|
if (window.sendEventCallback) {
|
|
48694
49326
|
window.sendEventCallback({
|
|
@@ -48706,36 +49338,36 @@ function requestLocation(componentID) {
|
|
|
48706
49338
|
}
|
|
48707
49339
|
|
|
48708
49340
|
function handleLocationError(error) {
|
|
48709
|
-
let errorMessage = "
|
|
48710
|
-
let errorCode = "
|
|
48711
|
-
|
|
49341
|
+
let errorMessage = "Location unknown error";
|
|
49342
|
+
let errorCode = "011";
|
|
49343
|
+
|
|
48712
49344
|
switch (error.code) {
|
|
48713
49345
|
case error.PERMISSION_DENIED:
|
|
48714
|
-
errorMessage = "Location permission denied
|
|
49346
|
+
errorMessage = "Location permission denied";
|
|
48715
49347
|
errorCode = "008";
|
|
48716
49348
|
break;
|
|
48717
49349
|
case error.POSITION_UNAVAILABLE:
|
|
48718
|
-
errorMessage = "Location
|
|
49350
|
+
errorMessage = "Location unavailable";
|
|
48719
49351
|
errorCode = "009";
|
|
48720
49352
|
break;
|
|
48721
49353
|
case error.TIMEOUT:
|
|
48722
|
-
errorMessage = "Location request
|
|
49354
|
+
errorMessage = "Location request timeout";
|
|
48723
49355
|
errorCode = "010";
|
|
48724
49356
|
break;
|
|
48725
49357
|
default:
|
|
48726
|
-
errorMessage = "
|
|
49358
|
+
errorMessage = "Location unknown error";
|
|
48727
49359
|
errorCode = "011";
|
|
48728
49360
|
break;
|
|
48729
49361
|
}
|
|
48730
|
-
|
|
49362
|
+
|
|
48731
49363
|
showLocationError(errorMessage);
|
|
48732
49364
|
console.error("Geolocation error:", error);
|
|
48733
|
-
|
|
49365
|
+
|
|
48734
49366
|
// Send error event
|
|
48735
49367
|
if (window.sendEventCallback) {
|
|
48736
49368
|
window.sendEventCallback({
|
|
48737
49369
|
type: "ERROR",
|
|
48738
|
-
|
|
49370
|
+
errorMessage: \`ErrorCode : \${errorCode}, \${errorMessage}\`,
|
|
48739
49371
|
data: { technicalError: error, reason: errorMessage }
|
|
48740
49372
|
});
|
|
48741
49373
|
}
|
|
@@ -48760,9 +49392,9 @@ function showLocationError(message) {
|
|
|
48760
49392
|
text-align: center;
|
|
48761
49393
|
\`;
|
|
48762
49394
|
errorDiv.textContent = message;
|
|
48763
|
-
|
|
49395
|
+
|
|
48764
49396
|
document.body.appendChild(errorDiv);
|
|
48765
|
-
|
|
49397
|
+
|
|
48766
49398
|
// Remove after 5 seconds
|
|
48767
49399
|
setTimeout(() => {
|
|
48768
49400
|
if (errorDiv.parentNode) {
|
|
@@ -48805,15 +49437,18 @@ let capturedImageData = "";
|
|
|
48805
49437
|
function openCameraModal() {
|
|
48806
49438
|
injectCameraModalStyles();
|
|
48807
49439
|
|
|
49440
|
+
// Ensure clean slate: Remove any existing modal if present
|
|
48808
49441
|
const existingModal = document.getElementById("cameraModal");
|
|
49442
|
+
if (existingModal) {
|
|
49443
|
+
existingModal.remove();
|
|
49444
|
+
}
|
|
48809
49445
|
|
|
48810
49446
|
capturedImageData = "";
|
|
48811
49447
|
|
|
48812
|
-
|
|
48813
|
-
const modalHTML = \`
|
|
49448
|
+
const modalHTML = \`
|
|
48814
49449
|
<div id="cameraModal">
|
|
48815
49450
|
<div id="cameraContainer">
|
|
48816
|
-
<video id="cameraVideo"
|
|
49451
|
+
<video id="cameraVideo" playsinline webkit-playsinline muted style="opacity: 0; pointer-events: none;"></video>
|
|
48817
49452
|
<div id="cameraLoader">
|
|
48818
49453
|
<div class="loader-spinner"></div>
|
|
48819
49454
|
<p class="loader-text">Starting camera...</p>
|
|
@@ -48824,6 +49459,11 @@ function openCameraModal() {
|
|
|
48824
49459
|
<path d="M18 6L6 18M6 6L18 18" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
48825
49460
|
</svg>
|
|
48826
49461
|
</button>
|
|
49462
|
+
<div class="camera-select-container">
|
|
49463
|
+
<select id="cameraSelect" class="camera-select">
|
|
49464
|
+
<option value="" disabled selected>Select Camera</option>
|
|
49465
|
+
</select>
|
|
49466
|
+
</div>
|
|
48827
49467
|
<div id="captureButton" style="opacity: 0; pointer-events: none;">
|
|
48828
49468
|
<div class="capture-ring">
|
|
48829
49469
|
<div class="capture-inner"></div>
|
|
@@ -48833,35 +49473,18 @@ function openCameraModal() {
|
|
|
48833
49473
|
</div>
|
|
48834
49474
|
</div>
|
|
48835
49475
|
\`;
|
|
48836
|
-
|
|
48837
|
-
|
|
48838
|
-
|
|
48839
|
-
|
|
48840
|
-
|
|
48841
|
-
|
|
48842
|
-
// Reset UI state when reopening
|
|
48843
|
-
const video = document.getElementById("cameraVideo");
|
|
48844
|
-
const loader = document.getElementById("cameraLoader");
|
|
48845
|
-
const captureBtn = document.getElementById("captureButton");
|
|
48846
|
-
|
|
48847
|
-
if (video) {
|
|
48848
|
-
video.style.opacity = "0";
|
|
48849
|
-
video.srcObject = null;
|
|
48850
|
-
}
|
|
48851
|
-
if (loader) {
|
|
48852
|
-
loader.style.display = "flex";
|
|
48853
|
-
loader.style.opacity = "1";
|
|
48854
|
-
}
|
|
48855
|
-
if (captureBtn) {
|
|
48856
|
-
captureBtn.style.opacity = "0";
|
|
48857
|
-
captureBtn.style.pointerEvents = "none";
|
|
48858
|
-
}
|
|
48859
|
-
}
|
|
49476
|
+
document.body.insertAdjacentHTML("beforeend", modalHTML);
|
|
49477
|
+
document.getElementById("closeCameraBtn").addEventListener("click", closeCameraModal);
|
|
49478
|
+
document.getElementById("captureButton").addEventListener("click", captureImage);
|
|
49479
|
+
document.getElementById("cameraSelect").addEventListener("change", (e) => {
|
|
49480
|
+
startCameraStream(e.target.value);
|
|
49481
|
+
});
|
|
48860
49482
|
|
|
49483
|
+
// Small delay to ensure DOM is ready
|
|
48861
49484
|
setTimeout(startCameraStream, 100);
|
|
48862
49485
|
}
|
|
48863
49486
|
|
|
48864
|
-
async function startCameraStream() {
|
|
49487
|
+
async function startCameraStream(deviceId = null) {
|
|
48865
49488
|
if (videoStream) {
|
|
48866
49489
|
try {
|
|
48867
49490
|
videoStream.getTracks().forEach(track => track.stop());
|
|
@@ -48872,42 +49495,84 @@ async function startCameraStream() {
|
|
|
48872
49495
|
}
|
|
48873
49496
|
|
|
48874
49497
|
try {
|
|
49498
|
+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (window.platform && window.platform.iosPlatform);
|
|
49499
|
+
|
|
49500
|
+
// Check if API is supported
|
|
49501
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
49502
|
+
const errorMsg = "Camera API is not supported. Please ensure you are using HTTPS or localhost.";
|
|
49503
|
+
alert(errorMsg);
|
|
49504
|
+
showCameraError(errorMsg);
|
|
49505
|
+
return;
|
|
49506
|
+
}
|
|
49507
|
+
|
|
48875
49508
|
const video = document.getElementById("cameraVideo");
|
|
48876
49509
|
if (!video) {
|
|
48877
49510
|
alert("Camera video element not found.");
|
|
48878
49511
|
return;
|
|
48879
49512
|
}
|
|
48880
49513
|
|
|
48881
|
-
//
|
|
48882
|
-
|
|
48883
|
-
|
|
49514
|
+
// Simplified approach: Ask for camera directly.
|
|
49515
|
+
// This allows the browser to handle permissions correctly on all platforms (Windows/Android/iOS)
|
|
49516
|
+
// and defaults to the system default camera (webcam) on laptops.
|
|
49517
|
+
// Simplified approach: Ask for camera directly.
|
|
49518
|
+
// We race against a timeout because WebViews often hang indefinitely if permissions aren't handled.
|
|
49519
|
+
// OPTIMIZATION: Request 16:9 aspect ratio (1280x720) instead of 4:3 (640x480).
|
|
49520
|
+
// This reduces the "zoom" effect on modern mobile screens which are typically 16:9 or taller.
|
|
49521
|
+
const constraints = {
|
|
49522
|
+
video: {
|
|
49523
|
+
width: { ideal: 1280 },
|
|
49524
|
+
height: { ideal: 720 }
|
|
49525
|
+
}
|
|
49526
|
+
};
|
|
48884
49527
|
|
|
48885
|
-
if (
|
|
48886
|
-
|
|
48887
|
-
|
|
49528
|
+
if (deviceId) {
|
|
49529
|
+
constraints.video.deviceId = { exact: deviceId };
|
|
49530
|
+
} else {
|
|
49531
|
+
constraints.video.facingMode = "environment";
|
|
48888
49532
|
}
|
|
48889
49533
|
|
|
48890
|
-
|
|
48891
|
-
const backCamera = videoDevices.find(device =>
|
|
48892
|
-
device.label.toLowerCase().includes('back') ||
|
|
48893
|
-
device.label.toLowerCase().includes('rear')
|
|
48894
|
-
) || videoDevices[0];
|
|
49534
|
+
const streamPromise = navigator.mediaDevices.getUserMedia(constraints);
|
|
48895
49535
|
|
|
48896
|
-
|
|
48897
|
-
|
|
48898
|
-
|
|
48899
|
-
|
|
48900
|
-
|
|
48901
|
-
|
|
49536
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
49537
|
+
setTimeout(() => reject(new Error("PermissionTimeout")), 6000)
|
|
49538
|
+
);
|
|
49539
|
+
|
|
49540
|
+
try {
|
|
49541
|
+
videoStream = await Promise.race([streamPromise, timeoutPromise]);
|
|
49542
|
+
} catch (err) {
|
|
49543
|
+
if (err.message === "PermissionTimeout") {
|
|
49544
|
+
throw new Error("Permission request timed out. Please check app permissions.");
|
|
48902
49545
|
}
|
|
48903
|
-
|
|
49546
|
+
throw err;
|
|
49547
|
+
}
|
|
48904
49548
|
|
|
49549
|
+
// iOS Specific: Ensure inline playback setup BEFORE stream assignment
|
|
49550
|
+
if (isIOS) {
|
|
49551
|
+
video.setAttribute("playsinline", "");
|
|
49552
|
+
video.setAttribute("webkit-playsinline", "");
|
|
49553
|
+
video.playsInline = true; // Set property as well
|
|
49554
|
+
}
|
|
49555
|
+
|
|
49556
|
+
// Mute video to prevent audio feedback and allow autoplay in restrictive policies
|
|
49557
|
+
video.muted = true;
|
|
49558
|
+
|
|
49559
|
+
// Assign stream
|
|
48905
49560
|
video.srcObject = videoStream;
|
|
48906
49561
|
|
|
49562
|
+
// Ensure video doesn't stay paused if it somehow exits fullscreen or gets interrupted
|
|
49563
|
+
video.onpause = () => {
|
|
49564
|
+
if (cameraStarted && video.srcObject) {
|
|
49565
|
+
// Only try to resume if we expect it to be playing
|
|
49566
|
+
video.play().catch(e => console.log("Resume error", e));
|
|
49567
|
+
}
|
|
49568
|
+
};
|
|
49569
|
+
|
|
48907
49570
|
// Wait for video to start playing, then hide loader
|
|
48908
49571
|
video.onloadedmetadata = () => {
|
|
48909
|
-
|
|
48910
|
-
|
|
49572
|
+
// Once permission is granted and stream starts, listing devices will return labels
|
|
49573
|
+
populateCameraDevices();
|
|
49574
|
+
|
|
49575
|
+
const showUI = () => {
|
|
48911
49576
|
const loader = document.getElementById("cameraLoader");
|
|
48912
49577
|
const captureBtn = document.getElementById("captureButton");
|
|
48913
49578
|
|
|
@@ -48915,23 +49580,34 @@ async function startCameraStream() {
|
|
|
48915
49580
|
loader.style.display = "none";
|
|
48916
49581
|
loader.style.opacity = "0";
|
|
48917
49582
|
}
|
|
49583
|
+
|
|
48918
49584
|
video.style.opacity = "1";
|
|
49585
|
+
|
|
48919
49586
|
if (captureBtn) {
|
|
48920
49587
|
captureBtn.style.opacity = "1";
|
|
48921
49588
|
captureBtn.style.pointerEvents = "all";
|
|
48922
49589
|
}
|
|
49590
|
+
};
|
|
48923
49591
|
|
|
49592
|
+
video.play().then(() => {
|
|
49593
|
+
showUI();
|
|
48924
49594
|
cameraStarted = true;
|
|
48925
49595
|
}).catch(err => {
|
|
48926
49596
|
console.error("Video play error:", err);
|
|
48927
|
-
|
|
48928
|
-
|
|
49597
|
+
if (!video.paused) {
|
|
49598
|
+
console.log("Video is playing despite error. Continuing.");
|
|
49599
|
+
showUI();
|
|
49600
|
+
cameraStarted = true;
|
|
49601
|
+
} else {
|
|
49602
|
+
alert("Failed to start video preview: " + err.message);
|
|
49603
|
+
closeCameraModal();
|
|
49604
|
+
}
|
|
48929
49605
|
});
|
|
48930
49606
|
};
|
|
48931
49607
|
|
|
48932
49608
|
} catch (err) {
|
|
48933
49609
|
console.error("Camera start error:", err);
|
|
48934
|
-
let errorMessage = "Failed to start camera";
|
|
49610
|
+
let errorMessage = err.message || "Failed to start camera";
|
|
48935
49611
|
|
|
48936
49612
|
if (err.name === 'NotAllowedError' || err.name === 'PermissionDeniedError') {
|
|
48937
49613
|
errorMessage = "Camera permission denied. Please allow camera access and try again.";
|
|
@@ -48947,18 +49623,50 @@ async function startCameraStream() {
|
|
|
48947
49623
|
errorMessage = "Camera access was interrupted.";
|
|
48948
49624
|
}
|
|
48949
49625
|
|
|
48950
|
-
|
|
49626
|
+
alert(errorMessage);
|
|
49627
|
+
closeCameraModal();
|
|
49628
|
+
}
|
|
49629
|
+
}
|
|
49630
|
+
|
|
49631
|
+
async function populateCameraDevices() {
|
|
49632
|
+
const select = document.getElementById("cameraSelect");
|
|
49633
|
+
if (!select) return;
|
|
48951
49634
|
|
|
48952
|
-
|
|
48953
|
-
|
|
48954
|
-
|
|
48955
|
-
|
|
48956
|
-
|
|
48957
|
-
|
|
49635
|
+
try {
|
|
49636
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
49637
|
+
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
|
49638
|
+
|
|
49639
|
+
// Only show if we have more than 1 camera, or at least we want to show the current one
|
|
49640
|
+
if (videoDevices.length > 0) {
|
|
49641
|
+
select.innerHTML = '<option value="" disabled>Select Camera</option>';
|
|
49642
|
+
|
|
49643
|
+
let currentDeviceId = "";
|
|
49644
|
+
if (videoStream) {
|
|
49645
|
+
const track = videoStream.getVideoTracks()[0];
|
|
49646
|
+
if (track) {
|
|
49647
|
+
const settings = track.getSettings();
|
|
49648
|
+
currentDeviceId = settings.deviceId;
|
|
49649
|
+
}
|
|
49650
|
+
}
|
|
49651
|
+
|
|
49652
|
+
videoDevices.forEach((device, index) => {
|
|
49653
|
+
const option = document.createElement("option");
|
|
49654
|
+
option.value = device.deviceId;
|
|
49655
|
+
option.text = device.label || \`Camera \${index + 1}\`;
|
|
49656
|
+
if (device.deviceId === currentDeviceId) {
|
|
49657
|
+
option.selected = true;
|
|
49658
|
+
}
|
|
49659
|
+
select.appendChild(option);
|
|
48958
49660
|
});
|
|
48959
|
-
}
|
|
48960
49661
|
|
|
48961
|
-
|
|
49662
|
+
// If there are multiple devices, ensure the dropdown container is visible
|
|
49663
|
+
const container = document.querySelector('.camera-select-container');
|
|
49664
|
+
if (container) {
|
|
49665
|
+
container.style.display = videoDevices.length > 1 ? 'block' : 'none';
|
|
49666
|
+
}
|
|
49667
|
+
}
|
|
49668
|
+
} catch (e) {
|
|
49669
|
+
console.warn("Error enumerating devices:", e);
|
|
48962
49670
|
}
|
|
48963
49671
|
}
|
|
48964
49672
|
|
|
@@ -49028,19 +49736,19 @@ function closeCameraModal() {
|
|
|
49028
49736
|
const modal = document.getElementById("cameraModal");
|
|
49029
49737
|
|
|
49030
49738
|
if (videoStream) {
|
|
49031
|
-
|
|
49739
|
+
try {
|
|
49740
|
+
videoStream.getTracks().forEach(track => track.stop());
|
|
49741
|
+
} catch (e) {
|
|
49742
|
+
console.warn("Error stopping tracks", e);
|
|
49743
|
+
}
|
|
49032
49744
|
videoStream = null;
|
|
49033
49745
|
cameraStarted = false;
|
|
49034
49746
|
}
|
|
49035
49747
|
|
|
49036
|
-
//
|
|
49037
|
-
|
|
49038
|
-
|
|
49039
|
-
video.srcObject = null;
|
|
49040
|
-
video.style.opacity = "0";
|
|
49748
|
+
// Completely remove from DOM to reset video element state for iOS
|
|
49749
|
+
if (modal) {
|
|
49750
|
+
modal.remove();
|
|
49041
49751
|
}
|
|
49042
|
-
|
|
49043
|
-
if (modal) modal.style.display = "none";
|
|
49044
49752
|
}
|
|
49045
49753
|
|
|
49046
49754
|
function injectCameraModalStyles() {
|
|
@@ -49071,6 +49779,7 @@ function injectCameraModalStyles() {
|
|
|
49071
49779
|
object-fit: cover;
|
|
49072
49780
|
background: #000;
|
|
49073
49781
|
transition: opacity 0.3s ease;
|
|
49782
|
+
pointer-events: none;
|
|
49074
49783
|
}
|
|
49075
49784
|
|
|
49076
49785
|
#cameraLoader {
|
|
@@ -49151,6 +49860,39 @@ function injectCameraModalStyles() {
|
|
|
49151
49860
|
background: rgba(0, 0, 0, 0.7);
|
|
49152
49861
|
}
|
|
49153
49862
|
|
|
49863
|
+
.camera-select-container {
|
|
49864
|
+
position: absolute;
|
|
49865
|
+
top: 20px;
|
|
49866
|
+
right: 20px;
|
|
49867
|
+
z-index: 10001;
|
|
49868
|
+
pointer-events: all;
|
|
49869
|
+
display: none; /* Hidden by default until devices found */
|
|
49870
|
+
}
|
|
49871
|
+
|
|
49872
|
+
.camera-select {
|
|
49873
|
+
background: rgba(0, 0, 0, 0.5);
|
|
49874
|
+
color: white;
|
|
49875
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
49876
|
+
padding: 8px 12px;
|
|
49877
|
+
border-radius: 20px;
|
|
49878
|
+
font-size: 14px;
|
|
49879
|
+
backdrop-filter: blur(10px);
|
|
49880
|
+
outline: none;
|
|
49881
|
+
cursor: pointer;
|
|
49882
|
+
appearance: none;
|
|
49883
|
+
-webkit-appearance: none;
|
|
49884
|
+
padding-right: 30px;
|
|
49885
|
+
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E");
|
|
49886
|
+
background-repeat: no-repeat;
|
|
49887
|
+
background-position: right 10px center;
|
|
49888
|
+
background-size: 10px;
|
|
49889
|
+
}
|
|
49890
|
+
|
|
49891
|
+
.camera-select option {
|
|
49892
|
+
background: #333;
|
|
49893
|
+
color: white;
|
|
49894
|
+
}
|
|
49895
|
+
|
|
49154
49896
|
#captureButton {
|
|
49155
49897
|
position: absolute;
|
|
49156
49898
|
bottom: 40px;
|
|
@@ -49217,6 +49959,11 @@ function injectCameraModalStyles() {
|
|
|
49217
49959
|
bottom: env(safe-area-inset-bottom, 40px);
|
|
49218
49960
|
bottom: max(40px, env(safe-area-inset-bottom));
|
|
49219
49961
|
}
|
|
49962
|
+
|
|
49963
|
+
.camera-select-container {
|
|
49964
|
+
top: env(safe-area-inset-top, 20px);
|
|
49965
|
+
top: max(20px, env(safe-area-inset-top));
|
|
49966
|
+
}
|
|
49220
49967
|
}
|
|
49221
49968
|
|
|
49222
49969
|
/* Landscape mode adjustments */
|
|
@@ -49851,7 +50598,7 @@ see README and LICENSE for details
|
|
|
49851
50598
|
|
|
49852
50599
|
let flag = false;
|
|
49853
50600
|
class SmartStorage {
|
|
49854
|
-
constructor() {}
|
|
50601
|
+
constructor() { }
|
|
49855
50602
|
|
|
49856
50603
|
static get title() {
|
|
49857
50604
|
return "SmartStorage";
|
|
@@ -49877,15 +50624,38 @@ class SmartStorage {
|
|
|
49877
50624
|
|
|
49878
50625
|
return new Promise((resolve, reject) => {
|
|
49879
50626
|
const request = indexedDB.open("Forms-Attachments", 3);
|
|
50627
|
+
|
|
49880
50628
|
request.onsuccess = function (event) {
|
|
49881
50629
|
const db = event.target.result;
|
|
50630
|
+
if (!db.objectStoreNames.contains("Files")) {
|
|
50631
|
+
console.warn("[SmartStorage] Files store missing. Recreating database.");
|
|
50632
|
+
db.close();
|
|
50633
|
+
const deleteReq = indexedDB.deleteDatabase("Forms-Attachments");
|
|
50634
|
+
deleteReq.onsuccess = () => {
|
|
50635
|
+
const retryReq = indexedDB.open("Forms-Attachments", 3);
|
|
50636
|
+
retryReq.onupgradeneeded = (e) => {
|
|
50637
|
+
const newDb = e.target.result;
|
|
50638
|
+
newDb.createObjectStore("Files");
|
|
50639
|
+
};
|
|
50640
|
+
retryReq.onsuccess = (e) => resolve(e.target.result);
|
|
50641
|
+
retryReq.onerror = (e) => reject(e);
|
|
50642
|
+
};
|
|
50643
|
+
deleteReq.onerror = (e) => reject(e);
|
|
50644
|
+
return;
|
|
50645
|
+
}
|
|
49882
50646
|
resolve(db);
|
|
49883
50647
|
};
|
|
49884
50648
|
|
|
49885
50649
|
request.onupgradeneeded = function (e) {
|
|
49886
50650
|
const db = e.target.result;
|
|
49887
|
-
db.
|
|
49888
|
-
|
|
50651
|
+
if (!db.objectStoreNames.contains("Files")) {
|
|
50652
|
+
db.createObjectStore("Files");
|
|
50653
|
+
}
|
|
50654
|
+
resolve(db); // Note: resolve here calls with incomplete db during upgrade transaction, but it's typically fine for callers waiting on db handle.
|
|
50655
|
+
// Ideally we resolve in onsuccess, but existing code had it this way too?
|
|
50656
|
+
// Actually, in the original code, it resolved in BOTH. Resolving in upgrade gives the transaction-bound db.
|
|
50657
|
+
// But Standard practice is waiting for success.
|
|
50658
|
+
// The original code had \`resolve(db)\` in \`onupgradeneeded\`.
|
|
49889
50659
|
};
|
|
49890
50660
|
|
|
49891
50661
|
request.onerror = function (e) {
|
|
@@ -49912,6 +50682,7 @@ class SmartStorage {
|
|
|
49912
50682
|
size: file.size,
|
|
49913
50683
|
type: file.type,
|
|
49914
50684
|
url,
|
|
50685
|
+
mode: "A",
|
|
49915
50686
|
};
|
|
49916
50687
|
if (
|
|
49917
50688
|
window.platform.isBrowser ||
|
|
@@ -49933,6 +50704,7 @@ class SmartStorage {
|
|
|
49933
50704
|
type: file.type,
|
|
49934
50705
|
url: url,
|
|
49935
50706
|
id,
|
|
50707
|
+
mode: "A",
|
|
49936
50708
|
});
|
|
49937
50709
|
};
|
|
49938
50710
|
} else {
|
|
@@ -49943,6 +50715,7 @@ class SmartStorage {
|
|
|
49943
50715
|
type: file.type,
|
|
49944
50716
|
url: url,
|
|
49945
50717
|
id,
|
|
50718
|
+
mode: "A",
|
|
49946
50719
|
});
|
|
49947
50720
|
}
|
|
49948
50721
|
};
|
|
@@ -50029,6 +50802,7 @@ class SmartStorage {
|
|
|
50029
50802
|
size: blobObject.size,
|
|
50030
50803
|
type: file.type,
|
|
50031
50804
|
url: file.url,
|
|
50805
|
+
mode: file.mode || "G",
|
|
50032
50806
|
};
|
|
50033
50807
|
const trans = db.transaction(["Files"], "readwrite");
|
|
50034
50808
|
const addReq = trans.objectStore("Files").put(data, id);
|
|
@@ -50688,7 +51462,21 @@ class SmartFileComponent extends FieldComponent {
|
|
|
50688
51462
|
}
|
|
50689
51463
|
|
|
50690
51464
|
getValue() {
|
|
50691
|
-
|
|
51465
|
+
const value = Array.isArray(this.dataValue) ? this.dataValue : (this.dataValue ? [this.dataValue] : []);
|
|
51466
|
+
return value.concat(this.deletedFiles || []);
|
|
51467
|
+
}
|
|
51468
|
+
|
|
51469
|
+
setValue(value, flags) {
|
|
51470
|
+
if (Array.isArray(value)) {
|
|
51471
|
+
this.deletedFiles = value.filter(f => f.mode === 'D');
|
|
51472
|
+
value = value.filter(f => f.mode !== 'D');
|
|
51473
|
+
} else if (value && value.mode === 'D') {
|
|
51474
|
+
this.deletedFiles = [value];
|
|
51475
|
+
value = [];
|
|
51476
|
+
} else {
|
|
51477
|
+
this.deletedFiles = [];
|
|
51478
|
+
}
|
|
51479
|
+
return super.setValue(value, flags);
|
|
50692
51480
|
}
|
|
50693
51481
|
|
|
50694
51482
|
get defaultValue() {
|
|
@@ -51011,6 +51799,13 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51011
51799
|
new SmartStorage().markFileAsDeleted(fileInfo.id);
|
|
51012
51800
|
this.deleteFile(fileInfo);
|
|
51013
51801
|
event.preventDefault();
|
|
51802
|
+
|
|
51803
|
+
fileInfo.mode = "D";
|
|
51804
|
+
if (!this.deletedFiles) {
|
|
51805
|
+
this.deletedFiles = [];
|
|
51806
|
+
}
|
|
51807
|
+
this.deletedFiles.push(fileInfo);
|
|
51808
|
+
|
|
51014
51809
|
this.splice(index);
|
|
51015
51810
|
this.redraw();
|
|
51016
51811
|
});
|
|
@@ -51265,10 +52060,8 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51265
52060
|
let id = this.component.id;
|
|
51266
52061
|
isfileBrowse = false;
|
|
51267
52062
|
|
|
51268
|
-
//
|
|
51269
|
-
|
|
51270
|
-
|
|
51271
|
-
if (window.platform.isAndroid) {
|
|
52063
|
+
// Dispatch custom camera event for both Android and iOS
|
|
52064
|
+
if (window.platform.isAndroid || window.platform.iosPlatform) {
|
|
51272
52065
|
window.isListenerSet = false;
|
|
51273
52066
|
let eventCustom = new CustomEvent("openCamera", {
|
|
51274
52067
|
detail: {
|
|
@@ -51652,6 +52445,24 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51652
52445
|
if (this.component.storage && files && files.length) {
|
|
51653
52446
|
// if (this.component.storage && files) {
|
|
51654
52447
|
Array.prototype.forEach.call(files, async (file) => {
|
|
52448
|
+
// Modify iOS filenames with timestamp BEFORE duplicate check
|
|
52449
|
+
let originalFileName = file.name;
|
|
52450
|
+
if (window.platform.iosPlatform) {
|
|
52451
|
+
const fileNameOriginal = file.name;
|
|
52452
|
+
const lastDotIndex = fileNameOriginal.lastIndexOf(".");
|
|
52453
|
+
let newName = "";
|
|
52454
|
+
if (lastDotIndex !== -1) {
|
|
52455
|
+
newName = \`\${fileNameOriginal.substring(
|
|
52456
|
+
0,
|
|
52457
|
+
lastDotIndex
|
|
52458
|
+
)}-\${Date.now()}\${fileNameOriginal.substring(lastDotIndex)}\`;
|
|
52459
|
+
} else {
|
|
52460
|
+
newName = \`\${fileNameOriginal}-\${Date.now()}\`;
|
|
52461
|
+
}
|
|
52462
|
+
file = new File([file], newName, {
|
|
52463
|
+
type: file.type,
|
|
52464
|
+
});
|
|
52465
|
+
}
|
|
51655
52466
|
const fileName = uniqueName(
|
|
51656
52467
|
file.name,
|
|
51657
52468
|
this.component.fileNameTemplate,
|
|
@@ -51694,8 +52505,9 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51694
52505
|
// Check if file with the same name is being uploaded
|
|
51695
52506
|
var fileWithSameNameUploaded = false;
|
|
51696
52507
|
if (window.platform.iosPlatform) {
|
|
52508
|
+
// For iOS, compare using the escaped filename (after timestamp modification)
|
|
51697
52509
|
fileWithSameNameUploaded = this.dataValue.some(
|
|
51698
|
-
(fileStatus) => fileStatus.
|
|
52510
|
+
(fileStatus) => fileStatus.originalName === escapedFileName
|
|
51699
52511
|
);
|
|
51700
52512
|
} else {
|
|
51701
52513
|
fileWithSameNameUploaded = isfileBrowse
|
|
@@ -51905,19 +52717,27 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51905
52717
|
fileInfo.originalName = escapedFileName;
|
|
51906
52718
|
fileInfo.hash = fileUpload.hash;
|
|
51907
52719
|
fileInfo.compnentId = this.component.id;
|
|
52720
|
+
fileInfo.mode = fileUpload.mode || "A";
|
|
51908
52721
|
if (!this.hasValue()) {
|
|
51909
52722
|
this.dataValue = [];
|
|
51910
52723
|
}
|
|
51911
52724
|
if (replace) {
|
|
51912
|
-
let ind;
|
|
52725
|
+
let ind = -1;
|
|
51913
52726
|
for (let i = 0; i < this.dataValue.length; i++) {
|
|
51914
52727
|
if (this.dataValue[i].originalName == fileInfo.originalName) {
|
|
51915
52728
|
console.log("original name matches");
|
|
51916
52729
|
ind = i;
|
|
52730
|
+
break;
|
|
51917
52731
|
}
|
|
51918
52732
|
}
|
|
51919
52733
|
if (ind !== -1) {
|
|
51920
52734
|
let originalFileId = this.dataValue[ind].id;
|
|
52735
|
+
let originalFileMode = this.dataValue[ind].mode;
|
|
52736
|
+
|
|
52737
|
+
if (originalFileMode === "G" || originalFileMode === "M") {
|
|
52738
|
+
fileInfo.mode = "M";
|
|
52739
|
+
}
|
|
52740
|
+
|
|
51921
52741
|
console.log("originalFileId = " + originalFileId);
|
|
51922
52742
|
this.dataValue[ind] = fileInfo;
|
|
51923
52743
|
let eventCustom = new CustomEvent(
|
|
@@ -59464,7 +60284,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59464
60284
|
return {
|
|
59465
60285
|
...super.conditionOperatorsSettings,
|
|
59466
60286
|
valueComponent(classComp) {
|
|
59467
|
-
const valueComp = { ...
|
|
60287
|
+
const valueComp = { ...classComp, type: 'select' };
|
|
59468
60288
|
|
|
59469
60289
|
if (isSelectResourceWithObjectValue(classComp)) {
|
|
59470
60290
|
valueComp.reference = false;
|
|
@@ -59616,7 +60436,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59616
60436
|
return this.component.valueProperty;
|
|
59617
60437
|
}
|
|
59618
60438
|
// Force values datasource to use values without actually setting it on the component settings.
|
|
59619
|
-
|
|
60439
|
+
if (this.component.dataSrc === 'values') {
|
|
59620
60440
|
return 'value';
|
|
59621
60441
|
}
|
|
59622
60442
|
return '';
|
|
@@ -59654,10 +60474,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59654
60474
|
|
|
59655
60475
|
get shouldInitialLoad() {
|
|
59656
60476
|
if (this.component.widget === 'html5' &&
|
|
59657
|
-
|
|
59658
|
-
|
|
59659
|
-
|
|
59660
|
-
|
|
60477
|
+
this.isEntireObjectDisplay() &&
|
|
60478
|
+
this.component.searchField &&
|
|
60479
|
+
this.dataValue) {
|
|
60480
|
+
return false;
|
|
59661
60481
|
}
|
|
59662
60482
|
|
|
59663
60483
|
return super.shouldLoad;
|
|
@@ -59692,7 +60512,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59692
60512
|
if (this.component.multiple && _.isArray(this.dataValue) ? this.dataValue.find((val) => value === val) : (this.dataValue === value)) {
|
|
59693
60513
|
const selectData = this.selectData;
|
|
59694
60514
|
if (selectData) {
|
|
59695
|
-
const templateValue = this.component.reference && value && (value._id
|
|
60515
|
+
const templateValue = this.component.reference && value && (value._id ? value._id.toString() : value);
|
|
59696
60516
|
if (!this.templateData || !this.templateData[templateValue]) {
|
|
59697
60517
|
this.getOptionTemplate(data, value);
|
|
59698
60518
|
}
|
|
@@ -59719,7 +60539,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59719
60539
|
});
|
|
59720
60540
|
}
|
|
59721
60541
|
|
|
59722
|
-
|
|
60542
|
+
if (data.data) {
|
|
59723
60543
|
// checking additional fields in the template for the selected Entire Object option
|
|
59724
60544
|
const hasNestedFields = /item\\.data\\.\\w*/g.test(this.component.template);
|
|
59725
60545
|
data.data = this.isEntireObjectDisplay() && _.isObject(data.data) && !hasNestedFields ?
|
|
@@ -59738,8 +60558,8 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59738
60558
|
hasTranslator = this.i18next.translator;
|
|
59739
60559
|
}
|
|
59740
60560
|
if (!label || (hasTranslator && !this.t(label, {
|
|
59741
|
-
|
|
59742
|
-
|
|
60561
|
+
_userInput: true
|
|
60562
|
+
}))) return;
|
|
59743
60563
|
return hasTranslator ? template.replace(label, this.t(label, {
|
|
59744
60564
|
_userInput: true
|
|
59745
60565
|
})) : label;
|
|
@@ -59766,7 +60586,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59766
60586
|
// ...idPath
|
|
59767
60587
|
// };
|
|
59768
60588
|
|
|
59769
|
-
|
|
60589
|
+
const option = Object.assign({
|
|
59770
60590
|
value: this.getOptionValue(value),
|
|
59771
60591
|
label,
|
|
59772
60592
|
}, idPath);
|
|
@@ -59922,7 +60742,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59922
60742
|
if (this.root && this.root.options.editForm && this.root.options.editForm._id && this.root.options.editForm._id === item._id) return;
|
|
59923
60743
|
const itemValueAndLabel = this.selectValueAndLabel(item);
|
|
59924
60744
|
this.addOption(itemValueAndLabel.value, itemValueAndLabel.label, {}, _.get(item, this.component.idPath, String(index)));
|
|
59925
|
-
|
|
60745
|
+
|
|
59926
60746
|
});
|
|
59927
60747
|
if (this.choices) {
|
|
59928
60748
|
if ((this.component.dataSrc === 'masterdata') && this.component.masterdata) {
|
|
@@ -59964,10 +60784,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59964
60784
|
// If a value is provided, then select it.
|
|
59965
60785
|
if (!this.isEmpty()) {
|
|
59966
60786
|
if (localStorage.getItem('renderMode') === 'html') {
|
|
59967
|
-
|
|
59968
|
-
|
|
59969
|
-
|
|
59970
|
-
|
|
60787
|
+
var tmplt = this.component.template;
|
|
60788
|
+
var str1 = tmplt.substring(tmplt.lastIndexOf('.') + 1, tmplt.length);
|
|
60789
|
+
var label = str1.substring(0, str1.indexOf('}'), str1.length);
|
|
60790
|
+
label = label.trim();
|
|
59971
60791
|
|
|
59972
60792
|
if (items.length > 0) {
|
|
59973
60793
|
if (this.component.multiple) {
|
|
@@ -59980,13 +60800,13 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59980
60800
|
});
|
|
59981
60801
|
} else {
|
|
59982
60802
|
}
|
|
60803
|
+
}
|
|
60804
|
+
} else {
|
|
60805
|
+
this.setValue(this.dataValue, {
|
|
60806
|
+
noUpdateEvent: true
|
|
60807
|
+
});
|
|
59983
60808
|
}
|
|
59984
|
-
}else{
|
|
59985
|
-
this.setValue(this.dataValue, {
|
|
59986
|
-
noUpdateEvent: true
|
|
59987
|
-
});
|
|
59988
|
-
}
|
|
59989
|
-
}else if (this.shouldAddDefaultValue && !this.options.readOnly) {
|
|
60809
|
+
} else if (this.shouldAddDefaultValue && !this.options.readOnly) {
|
|
59990
60810
|
// If a default value is provided then select it.
|
|
59991
60811
|
const defaultValue = this.defaultValue;
|
|
59992
60812
|
if (!this.isEmpty(defaultValue)) {
|
|
@@ -60293,32 +61113,32 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60293
61113
|
} else {
|
|
60294
61114
|
if (!this.component.dropdownOpened && this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60295
61115
|
let result = [];
|
|
60296
|
-
if(this.component.multiple && this.component.masterdata){
|
|
60297
|
-
this.data[this.key].forEach(item =>
|
|
61116
|
+
if (this.component.multiple && this.component.masterdata) {
|
|
61117
|
+
this.data[this.key].forEach(item =>
|
|
60298
61118
|
this.component.masterdata.filter((value) => {
|
|
60299
61119
|
const propValue = value[this.component.valueProperty];
|
|
60300
|
-
|
|
60301
|
-
|
|
60302
|
-
if(valPropData.includes(item)){
|
|
61120
|
+
// Convert to string only if necessary
|
|
61121
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61122
|
+
if (valPropData.includes(item)) {
|
|
60303
61123
|
result.push(value)
|
|
60304
61124
|
}
|
|
60305
61125
|
})
|
|
60306
61126
|
);
|
|
60307
61127
|
// result = this.component.masterdata;
|
|
60308
|
-
}else{
|
|
60309
|
-
if(this.component.masterdata){
|
|
60310
|
-
|
|
60311
|
-
|
|
60312
|
-
|
|
60313
|
-
|
|
60314
|
-
|
|
60315
|
-
|
|
60316
|
-
|
|
61128
|
+
} else {
|
|
61129
|
+
if (this.component.masterdata) {
|
|
61130
|
+
result = this.component.masterdata.filter(value => {
|
|
61131
|
+
const propValue = value[this.component.valueProperty];
|
|
61132
|
+
// Convert to string only if necessary
|
|
61133
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61134
|
+
return valPropData?.includes(this.data[this.key]);
|
|
61135
|
+
});
|
|
61136
|
+
}
|
|
60317
61137
|
}
|
|
60318
61138
|
const unique = result.filter((obj, index) => {
|
|
60319
61139
|
return index === result.findIndex(o => obj[this.component.valueProperty] === o[this.component.valueProperty]);
|
|
60320
|
-
|
|
60321
|
-
|
|
61140
|
+
});
|
|
61141
|
+
this.setItems(unique);
|
|
60322
61142
|
}
|
|
60323
61143
|
}
|
|
60324
61144
|
}
|
|
@@ -60479,9 +61299,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60479
61299
|
get active() {
|
|
60480
61300
|
if ((this.component.dataSrc === 'masterdata') && this.component.masterdata) {
|
|
60481
61301
|
return !this.component.lazyLoad || this.activated;
|
|
60482
|
-
}else{
|
|
60483
|
-
|
|
60484
|
-
|
|
61302
|
+
} else {
|
|
61303
|
+
// return !this.component.lazyLoad || this.activated || this.options.readOnly;
|
|
61304
|
+
return !this.component.lazyLoad || this.activated;
|
|
60485
61305
|
}
|
|
60486
61306
|
}
|
|
60487
61307
|
|
|
@@ -60555,8 +61375,8 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60555
61375
|
searchChoices: !this.component.searchField,
|
|
60556
61376
|
searchFields: _.get(this, 'component.searchFields', ['label']),
|
|
60557
61377
|
shadowRoot: this.root ? this.root.shadowRoot : null,
|
|
60558
|
-
|
|
60559
|
-
_.get(this, 'component.fuseOptions', {}),
|
|
61378
|
+
fuseOptions: this.component.useExactSearch ? Object.assign(fuseObj, commonFuseOptions) : Object.assign({},
|
|
61379
|
+
_.get(this, 'component.fuseOptions', {}),
|
|
60560
61380
|
Object.assign(fuseObj1, commonFuseOptions)
|
|
60561
61381
|
),
|
|
60562
61382
|
valueComparer: _.isEqual,
|
|
@@ -60724,17 +61544,17 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60724
61544
|
}
|
|
60725
61545
|
this.isFromSearch = false;
|
|
60726
61546
|
});
|
|
60727
|
-
|
|
60728
|
-
|
|
60729
|
-
|
|
60730
|
-
|
|
60731
|
-
|
|
60732
|
-
|
|
60733
|
-
|
|
60734
|
-
|
|
60735
|
-
|
|
60736
|
-
|
|
60737
|
-
|
|
61547
|
+
// avoid spamming the resource/url endpoint when we have server side filtering enabled.
|
|
61548
|
+
const debounceTimeout = this.component.searchField && (this.isSelectResource || this.isSelectURL) ?
|
|
61549
|
+
(this.component.searchDebounce === 0 ? 0 : this.component.searchDebounce || this.defaultSchema.searchDebounce) * 1000
|
|
61550
|
+
: 0;
|
|
61551
|
+
const updateComponent = (evt) => {
|
|
61552
|
+
this.triggerUpdate(evt.detail.value);
|
|
61553
|
+
};
|
|
61554
|
+
this.addEventListener(input, 'search', _.debounce((e) => {
|
|
61555
|
+
updateComponent(e);
|
|
61556
|
+
this.positionDropdown();
|
|
61557
|
+
}, debounceTimeout));
|
|
60738
61558
|
|
|
60739
61559
|
this.addEventListener(input, 'stopSearch', () => this.triggerUpdate());
|
|
60740
61560
|
this.addEventListener(input, 'hideDropdown', () => {
|
|
@@ -60749,9 +61569,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60749
61569
|
if (this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60750
61570
|
selData = this.component.masterdata.filter((value) => {
|
|
60751
61571
|
const propValue = value[this.component.valueProperty];
|
|
60752
|
-
|
|
60753
|
-
|
|
60754
|
-
|
|
61572
|
+
// Convert to string only if necessary
|
|
61573
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61574
|
+
return valPropData?.includes(this.data[this.key]);
|
|
60755
61575
|
|
|
60756
61576
|
})
|
|
60757
61577
|
}
|
|
@@ -60844,10 +61664,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60844
61664
|
setDropdownPosition() {
|
|
60845
61665
|
let dropdown;
|
|
60846
61666
|
let container;
|
|
60847
|
-
if(this.choices && this.choices.dropdown && this.choices.dropdown.element){
|
|
60848
|
-
|
|
61667
|
+
if (this.choices && this.choices.dropdown && this.choices.dropdown.element) {
|
|
61668
|
+
dropdown = this.choices.dropdown.element;
|
|
60849
61669
|
}
|
|
60850
|
-
if(this.choices && this.choices.containerOuter && this.choices.containerOuter.element){
|
|
61670
|
+
if (this.choices && this.choices.containerOuter && this.choices.containerOuter.element) {
|
|
60851
61671
|
container = this.choices.containerOuter.element;
|
|
60852
61672
|
}
|
|
60853
61673
|
|
|
@@ -60932,9 +61752,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60932
61752
|
if (this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60933
61753
|
selData = this.component.masterdata.filter((value) => {
|
|
60934
61754
|
const propValue = value[this.component.valueProperty];
|
|
60935
|
-
|
|
60936
|
-
|
|
60937
|
-
|
|
61755
|
+
// Convert to string only if necessary
|
|
61756
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61757
|
+
return valPropData?.includes(this.data[this.key]);
|
|
60938
61758
|
})
|
|
60939
61759
|
}
|
|
60940
61760
|
|
|
@@ -61285,29 +62105,29 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61285
62105
|
|
|
61286
62106
|
setValue(value, flags = {}) {
|
|
61287
62107
|
// console.log("value line 1875" + this.component.label, value)
|
|
61288
|
-
if(value && String(value).length > 0){
|
|
62108
|
+
if (value && String(value).length > 0) {
|
|
61289
62109
|
$(".barcode-select-error").remove();
|
|
61290
62110
|
}
|
|
61291
|
-
|
|
61292
|
-
|
|
61293
|
-
|
|
61294
|
-
|
|
61295
|
-
|
|
61296
|
-
|
|
62111
|
+
if (localStorage.getItem('renderMode') === 'html' && this.component.dataSrc === 'values') {
|
|
62112
|
+
this.component.data.values.filter((data) => {
|
|
62113
|
+
if ((value && data.value === value) || (value && data.value === String(value))) {
|
|
62114
|
+
value = data.label;
|
|
62115
|
+
};
|
|
62116
|
+
})
|
|
62117
|
+
}
|
|
62118
|
+
if (localStorage.getItem('renderMode') === 'html' && this.component.dataSrc === 'masterdata' && !this.component.multiple) {
|
|
62119
|
+
var tmplt = this.component.template;
|
|
62120
|
+
var str1 = tmplt.substring(tmplt.lastIndexOf('.') + 1, tmplt.length);
|
|
62121
|
+
var label = str1.substring(0, str1.indexOf('}'), str1.length);
|
|
62122
|
+
label = label.trim();
|
|
62123
|
+
|
|
62124
|
+
this.component.masterdata.filter((data) => {
|
|
62125
|
+
if ((value && data[this.component.valueProperty] === value) || (value && data[this.component.valueProperty] === String(value))) {
|
|
62126
|
+
value = data[label];
|
|
62127
|
+
}
|
|
62128
|
+
})
|
|
61297
62129
|
}
|
|
61298
|
-
if (localStorage.getItem('renderMode') === 'html' && this.component.dataSrc === 'masterdata' && !this.component.multiple) {
|
|
61299
|
-
var tmplt = this.component.template;
|
|
61300
|
-
var str1 = tmplt.substring(tmplt.lastIndexOf('.') + 1, tmplt.length);
|
|
61301
|
-
var label = str1.substring(0, str1.indexOf('}'), str1.length);
|
|
61302
|
-
label = label.trim();
|
|
61303
62130
|
|
|
61304
|
-
this.component.masterdata.filter((data) => {
|
|
61305
|
-
if ((value && data[this.component.valueProperty] === value) || (value && data[this.component.valueProperty] === String(value))) {
|
|
61306
|
-
value = data[label];
|
|
61307
|
-
}
|
|
61308
|
-
})
|
|
61309
|
-
}
|
|
61310
|
-
|
|
61311
62131
|
const previousValue = this.dataValue;
|
|
61312
62132
|
// console.log("value line 1900 " + this.component.label, value)
|
|
61313
62133
|
const changed = this.updateValue(value, flags);
|
|
@@ -61319,10 +62139,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61319
62139
|
if (this.component.multiple && Array.isArray(value)) {
|
|
61320
62140
|
value = value.map(value => {
|
|
61321
62141
|
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
61322
|
-
|
|
62142
|
+
console.log("value line 1910 " + this.component.label, value)
|
|
61323
62143
|
return value.toString();
|
|
61324
62144
|
}
|
|
61325
|
-
|
|
62145
|
+
console.log("value line 1914 " + this.component.label, value)
|
|
61326
62146
|
return value;
|
|
61327
62147
|
});
|
|
61328
62148
|
} else {
|
|
@@ -61354,10 +62174,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61354
62174
|
// Add the value options.
|
|
61355
62175
|
this.itemsLoaded.then(() => {
|
|
61356
62176
|
this.addValueOptions();
|
|
61357
|
-
|
|
62177
|
+
// console.log("value line 1945 " + this.component.label, value)
|
|
61358
62178
|
this.setChoicesValue(value, hasPreviousValue, flags);
|
|
61359
62179
|
});
|
|
61360
|
-
|
|
62180
|
+
|
|
61361
62181
|
return changed;
|
|
61362
62182
|
}
|
|
61363
62183
|
|
|
@@ -61404,7 +62224,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61404
62224
|
if (hasValue) {
|
|
61405
62225
|
const values = Array.isArray(value) ? value : [value];
|
|
61406
62226
|
if (!_.isEqual(this.dataValue, this.defaultValue) && this.selectOptions.length < 2
|
|
61407
|
-
|
|
62227
|
+
|| (this.selectData && flags.fromSubmission)) {
|
|
61408
62228
|
const { value, label } = this.selectValueAndLabel(this.dataValue);
|
|
61409
62229
|
this.addOption(value, label);
|
|
61410
62230
|
}
|
|
@@ -61477,14 +62297,14 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61477
62297
|
*/
|
|
61478
62298
|
getOptionValue(value) {
|
|
61479
62299
|
return _.isObject(value) && this.isEntireObjectDisplay()
|
|
61480
|
-
|
|
61481
|
-
|
|
61482
|
-
|
|
61483
|
-
|
|
61484
|
-
|
|
61485
|
-
|
|
61486
|
-
|
|
61487
|
-
|
|
62300
|
+
? this.normalizeSingleValue(value)
|
|
62301
|
+
: _.isObject(value) && (this.valueProperty || this.component.key !== 'resource')
|
|
62302
|
+
? value
|
|
62303
|
+
: _.isObject(value) && !this.valueProperty
|
|
62304
|
+
? this.interpolate(this.component.template, { item: value }).replace(/<\\/?[^>]+(>|$)/g, '')
|
|
62305
|
+
: _.isNull(value)
|
|
62306
|
+
? this.emptyValue
|
|
62307
|
+
: String(this.normalizeSingleValue(value));
|
|
61488
62308
|
}
|
|
61489
62309
|
|
|
61490
62310
|
/**
|
|
@@ -61600,19 +62420,19 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61600
62420
|
items: convertToString(this.getNormalizedValues(), 'value'),
|
|
61601
62421
|
valueProperty: 'value',
|
|
61602
62422
|
} : {
|
|
61603
|
-
|
|
61604
|
-
|
|
61605
|
-
|
|
62423
|
+
items: convertToString(this.getCustomItems(), this.valueProperty),
|
|
62424
|
+
valueProperty: this.valueProperty,
|
|
62425
|
+
};
|
|
61606
62426
|
const getFromValues = () => {
|
|
61607
62427
|
const initialValue = _.find(items, [valueProperty, value]);
|
|
61608
62428
|
const values = this.defaultSchema.data.values || [];
|
|
61609
62429
|
return _.isEqual(initialValue, values[0]) ? '-' : initialValue;
|
|
61610
62430
|
};
|
|
61611
62431
|
value = (this.component.multiple && Array.isArray(value))
|
|
61612
|
-
|
|
61613
|
-
|
|
61614
|
-
|
|
61615
|
-
|
|
62432
|
+
? _.filter(items, (item) => value.includes(item.value))
|
|
62433
|
+
: valueProperty
|
|
62434
|
+
? getFromValues() ?? { value, label: value }
|
|
62435
|
+
: value;
|
|
61616
62436
|
}
|
|
61617
62437
|
|
|
61618
62438
|
if (_.isString(value)) {
|
|
@@ -61628,7 +62448,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61628
62448
|
if (Array.isArray(value)) {
|
|
61629
62449
|
const items = [];
|
|
61630
62450
|
value.forEach(item => items.push(getTemplateValue(item)));
|
|
61631
|
-
if (this.component.dataSrc === 'resource' &&
|
|
62451
|
+
if (this.component.dataSrc === 'resource' && items.length > 0) {
|
|
61632
62452
|
return items.join(', ');
|
|
61633
62453
|
}
|
|
61634
62454
|
else if (items.length > 0) {
|
|
@@ -64975,12 +65795,27 @@ function FormOnBackNavigation() {
|
|
|
64975
65795
|
function initialButtonSetup(privateExternal, permission) {
|
|
64976
65796
|
const saveBtn = document.getElementById("saveBtn");
|
|
64977
65797
|
const submitBtn = document.getElementById("submitBtn");
|
|
65798
|
+
const completeOption = document.getElementById("completeOption");
|
|
65799
|
+
const saveOption = document.getElementById("saveOption");
|
|
65800
|
+
const completeDivider = document.getElementById("completeDivider");
|
|
65801
|
+
const saveDivider = document.getElementById("saveDivider");
|
|
65802
|
+
|
|
64978
65803
|
if (!saveBtn || !submitBtn) return;
|
|
64979
65804
|
|
|
64980
65805
|
const isPrivate = privateExternal === true || privateExternal === "true";
|
|
64981
65806
|
const isPublic = privateExternal === false || privateExternal === "false";
|
|
64982
65807
|
const permissionMode = String(permission || "").toLowerCase();
|
|
64983
65808
|
|
|
65809
|
+
// Helper to toggle dropdown items
|
|
65810
|
+
const toggleDropdown = (option, divider, show) => {
|
|
65811
|
+
if (option) option.style.display = show ? "block" : "none";
|
|
65812
|
+
if (divider) divider.style.display = show ? "block" : "none";
|
|
65813
|
+
};
|
|
65814
|
+
|
|
65815
|
+
// Default: Hide dropdown specific items
|
|
65816
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65817
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
65818
|
+
|
|
64984
65819
|
// READ ONLY
|
|
64985
65820
|
if (permissionMode === "read") {
|
|
64986
65821
|
console.log("Mode: READ \u2192 Hide all buttons");
|
|
@@ -64988,31 +65823,72 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
64988
65823
|
submitBtn.style.display = "none";
|
|
64989
65824
|
}
|
|
64990
65825
|
|
|
64991
|
-
// PUBLIC FORM
|
|
64992
|
-
else if (
|
|
64993
|
-
|
|
64994
|
-
(permissionMode === "writesingle" || permissionMode === "writemultiple")
|
|
64995
|
-
) {
|
|
64996
|
-
console.log("Mode: PUBLIC WRITE \u2192 Show submit (disabled)");
|
|
65826
|
+
// PUBLIC FORM - writemultiple
|
|
65827
|
+
else if (isPublic && permissionMode === "writemultiple") {
|
|
65828
|
+
console.log("Mode: PUBLIC WRITEMULTIPLE \u2192 Show Complete button only (disabled)");
|
|
64997
65829
|
saveBtn.style.display = "none";
|
|
64998
65830
|
submitBtn.style.display = "";
|
|
65831
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
64999
65832
|
submitBtn.disabled = true;
|
|
65833
|
+
|
|
65834
|
+
// No dropdown options for public writemultiple
|
|
65835
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65836
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
65000
65837
|
}
|
|
65001
65838
|
|
|
65002
|
-
//
|
|
65003
|
-
else if (
|
|
65004
|
-
console.log("Mode:
|
|
65839
|
+
// PUBLIC FORM - writesingle
|
|
65840
|
+
else if (isPublic && permissionMode === "writesingle") {
|
|
65841
|
+
console.log("Mode: PUBLIC WRITESINGLE \u2192 Show submit (disabled)");
|
|
65005
65842
|
saveBtn.style.display = "none";
|
|
65006
65843
|
submitBtn.style.display = "";
|
|
65844
|
+
submitBtn.innerHTML = '<i class="icon save"></i> Submit';
|
|
65007
65845
|
submitBtn.disabled = true;
|
|
65008
65846
|
}
|
|
65009
65847
|
|
|
65848
|
+
// PRIVATE FORM - writemultiple
|
|
65849
|
+
else if (isPrivate && permissionMode === "writemultiple") {
|
|
65850
|
+
const showCompleteAlways =
|
|
65851
|
+
window.__unviredFormsOptions?.showCompleteAlways === true ||
|
|
65852
|
+
window.__unviredFormsOptions?.showCompleteAlways === "true";
|
|
65853
|
+
|
|
65854
|
+
if (showCompleteAlways) {
|
|
65855
|
+
console.log(
|
|
65856
|
+
"Mode: PRIVATE WRITEMULTIPLE (ShowCompleteAlways) \u2192 Show Save and Complete"
|
|
65857
|
+
);
|
|
65858
|
+
saveBtn.style.display = "";
|
|
65859
|
+
submitBtn.style.display = "";
|
|
65860
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65861
|
+
|
|
65862
|
+
saveBtn.disabled = true; // Initially empty
|
|
65863
|
+
submitBtn.disabled = true; // Initially not complete
|
|
65864
|
+
|
|
65865
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65866
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
65867
|
+
} else {
|
|
65868
|
+
console.log(
|
|
65869
|
+
"Mode: PRIVATE WRITEMULTIPLE \u2192 Show save (disabled), Complete hidden initially"
|
|
65870
|
+
);
|
|
65871
|
+
saveBtn.style.display = "";
|
|
65872
|
+
submitBtn.style.display = "none";
|
|
65873
|
+
saveBtn.disabled = true;
|
|
65874
|
+
|
|
65875
|
+
// Initially hide Complete in Dropdown (will show when any field is filled)
|
|
65876
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65877
|
+
}
|
|
65878
|
+
}
|
|
65879
|
+
|
|
65010
65880
|
// PRIVATE FORM - writesingle
|
|
65011
65881
|
else if (isPrivate && permissionMode === "writesingle") {
|
|
65012
|
-
console.log(
|
|
65013
|
-
|
|
65014
|
-
|
|
65015
|
-
saveBtn.
|
|
65882
|
+
console.log(
|
|
65883
|
+
"Mode: PRIVATE WRITESINGLE \u2192 Show submit (disabled), Save in Dropdown"
|
|
65884
|
+
);
|
|
65885
|
+
saveBtn.style.display = "none";
|
|
65886
|
+
submitBtn.style.display = "";
|
|
65887
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65888
|
+
submitBtn.disabled = true;
|
|
65889
|
+
|
|
65890
|
+
// Show Save in Dropdown
|
|
65891
|
+
toggleDropdown(saveOption, saveDivider, true);
|
|
65016
65892
|
}
|
|
65017
65893
|
|
|
65018
65894
|
// DEFAULT / UNKNOWN
|
|
@@ -65020,8 +65896,14 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
65020
65896
|
console.log("Mode: DEFAULT / UNKNOWN \u2192 Show submit (disabled)");
|
|
65021
65897
|
saveBtn.style.display = "none";
|
|
65022
65898
|
submitBtn.style.display = "";
|
|
65899
|
+
submitBtn.innerHTML = '<i class="icon clipboard large"></i> Submit';
|
|
65023
65900
|
submitBtn.disabled = true;
|
|
65024
65901
|
}
|
|
65902
|
+
|
|
65903
|
+
// Check if More button should be visible based on dropdown content
|
|
65904
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
65905
|
+
window.checkMoreButtonVisibility();
|
|
65906
|
+
}
|
|
65025
65907
|
}
|
|
65026
65908
|
|
|
65027
65909
|
function onChangeButtonSetup(
|
|
@@ -65043,10 +65925,16 @@ function onChangeButtonSetup(
|
|
|
65043
65925
|
v !== undefined &&
|
|
65044
65926
|
v !== null &&
|
|
65045
65927
|
v !== "" &&
|
|
65046
|
-
|
|
65928
|
+
v !== false &&
|
|
65929
|
+
!(Array.isArray(v) && v.length === 0) &&
|
|
65930
|
+
!(typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0)
|
|
65047
65931
|
);
|
|
65048
65932
|
const isComplete = completionPercentage >= 100;
|
|
65049
65933
|
|
|
65934
|
+
const requireComplete =
|
|
65935
|
+
window.__unviredFormsOptions?.requireCompleteForm === true ||
|
|
65936
|
+
window.__unviredFormsOptions?.requireCompleteForm === "true";
|
|
65937
|
+
|
|
65050
65938
|
// READ ONLY
|
|
65051
65939
|
if (permissionMode === "read") {
|
|
65052
65940
|
console.log("Mode: READ \u2192 Hide all buttons");
|
|
@@ -65058,38 +65946,121 @@ function onChangeButtonSetup(
|
|
|
65058
65946
|
// PRIVATE FORM - writesingle
|
|
65059
65947
|
if (isPrivate && permissionMode === "writesingle") {
|
|
65060
65948
|
console.log("Mode: PRIVATE WRITESINGLE");
|
|
65949
|
+
// Main: Complete (Submit)
|
|
65061
65950
|
saveBtn.style.display = "none";
|
|
65062
65951
|
submitBtn.style.display = "";
|
|
65063
|
-
|
|
65952
|
+
|
|
65953
|
+
// Logic: Disable Complete until 100% if required, otherwise just check if has values
|
|
65954
|
+
submitBtn.disabled = requireComplete ? !isComplete : !hasAnyValue;
|
|
65955
|
+
|
|
65956
|
+
// Check if More button should be visible
|
|
65957
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
65958
|
+
window.checkMoreButtonVisibility();
|
|
65959
|
+
}
|
|
65064
65960
|
return;
|
|
65065
65961
|
}
|
|
65066
65962
|
|
|
65067
65963
|
// PRIVATE FORM - writemultiple
|
|
65068
65964
|
if (isPrivate && permissionMode === "writemultiple") {
|
|
65069
65965
|
console.log("Mode: PRIVATE WRITEMULTIPLE");
|
|
65070
|
-
|
|
65071
|
-
|
|
65072
|
-
|
|
65073
|
-
|
|
65074
|
-
|
|
65075
|
-
|
|
65076
|
-
|
|
65966
|
+
|
|
65967
|
+
const completeOption = document.getElementById("completeOption");
|
|
65968
|
+
const saveOption = document.getElementById("saveOption");
|
|
65969
|
+
const completeDivider = document.getElementById("completeDivider");
|
|
65970
|
+
const saveDivider = document.getElementById("saveDivider");
|
|
65971
|
+
|
|
65972
|
+
// Helper to toggle dropdown items
|
|
65973
|
+
const toggleDropdown = (option, divider, show) => {
|
|
65974
|
+
if (option) option.style.display = show ? "block" : "none";
|
|
65975
|
+
if (divider) divider.style.display = show ? "block" : "none";
|
|
65976
|
+
};
|
|
65977
|
+
|
|
65978
|
+
const showCompleteAlways =
|
|
65979
|
+
window.__unviredFormsOptions?.showCompleteAlways === true ||
|
|
65980
|
+
window.__unviredFormsOptions?.showCompleteAlways === "true";
|
|
65981
|
+
|
|
65982
|
+
if (showCompleteAlways) {
|
|
65077
65983
|
saveBtn.style.display = "";
|
|
65078
|
-
submitBtn.style.display = "
|
|
65984
|
+
submitBtn.style.display = "";
|
|
65985
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65986
|
+
|
|
65079
65987
|
saveBtn.disabled = !hasAnyValue;
|
|
65988
|
+
submitBtn.disabled = requireComplete ? !isComplete : !hasAnyValue;
|
|
65989
|
+
|
|
65990
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65991
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
65992
|
+
} else {
|
|
65993
|
+
if (isComplete) {
|
|
65994
|
+
// 100% Complete: Main button = Complete, Dropdown = Save
|
|
65995
|
+
console.log(
|
|
65996
|
+
" \u2192 100% Complete: Showing Complete button, Save in dropdown"
|
|
65997
|
+
);
|
|
65998
|
+
saveBtn.style.display = "none";
|
|
65999
|
+
submitBtn.style.display = "";
|
|
66000
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
66001
|
+
submitBtn.disabled = false;
|
|
66002
|
+
|
|
66003
|
+
// Show Save in dropdown, hide Complete
|
|
66004
|
+
toggleDropdown(saveOption, saveDivider, true);
|
|
66005
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
66006
|
+
} else if (hasAnyValue) {
|
|
66007
|
+
// 1-99% Complete: Main button = Save, Dropdown = Complete
|
|
66008
|
+
console.log(
|
|
66009
|
+
" \u2192 Partially filled: Showing Save button, Complete in dropdown"
|
|
66010
|
+
);
|
|
66011
|
+
saveBtn.style.display = "";
|
|
66012
|
+
submitBtn.style.display = "none";
|
|
66013
|
+
saveBtn.disabled = false;
|
|
66014
|
+
|
|
66015
|
+
// Show Complete in dropdown, hide Save
|
|
66016
|
+
toggleDropdown(completeOption, completeDivider, true);
|
|
66017
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
66018
|
+
} else {
|
|
66019
|
+
// 0% Complete: Main button = Save (disabled), Complete hidden
|
|
66020
|
+
console.log(" \u2192 Empty form: Save disabled, Complete hidden");
|
|
66021
|
+
saveBtn.style.display = "";
|
|
66022
|
+
submitBtn.style.display = "none";
|
|
66023
|
+
saveBtn.disabled = true;
|
|
66024
|
+
|
|
66025
|
+
// Hide both in dropdown
|
|
66026
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
66027
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
66028
|
+
}
|
|
66029
|
+
}
|
|
66030
|
+
|
|
66031
|
+
// Check if More button should be visible based on dropdown content
|
|
66032
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
66033
|
+
window.checkMoreButtonVisibility();
|
|
65080
66034
|
}
|
|
65081
66035
|
return;
|
|
65082
66036
|
}
|
|
65083
66037
|
|
|
65084
|
-
// PUBLIC FORM
|
|
65085
|
-
if (
|
|
65086
|
-
|
|
65087
|
-
(permissionMode === "writesingle" || permissionMode === "writemultiple")
|
|
65088
|
-
) {
|
|
65089
|
-
console.log("Mode: PUBLIC WRITE \u2192 Show submit");
|
|
66038
|
+
// PUBLIC FORM - writemultiple (Simple: Only Complete button)
|
|
66039
|
+
if (isPublic && permissionMode === "writemultiple") {
|
|
66040
|
+
console.log("Mode: PUBLIC WRITEMULTIPLE \u2192 Single Complete button");
|
|
65090
66041
|
saveBtn.style.display = "none";
|
|
65091
66042
|
submitBtn.style.display = "";
|
|
66043
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65092
66044
|
submitBtn.disabled = !hasAnyValue;
|
|
66045
|
+
|
|
66046
|
+
// Check if More button should be visible
|
|
66047
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
66048
|
+
window.checkMoreButtonVisibility();
|
|
66049
|
+
}
|
|
66050
|
+
return;
|
|
66051
|
+
}
|
|
66052
|
+
|
|
66053
|
+
// PUBLIC FORM - writesingle
|
|
66054
|
+
if (isPublic && permissionMode === "writesingle") {
|
|
66055
|
+
console.log("Mode: PUBLIC WRITESINGLE \u2192 Show submit");
|
|
66056
|
+
saveBtn.style.display = "none";
|
|
66057
|
+
submitBtn.style.display = "";
|
|
66058
|
+
submitBtn.disabled = !hasAnyValue;
|
|
66059
|
+
|
|
66060
|
+
// Check if More button should be visible
|
|
66061
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
66062
|
+
window.checkMoreButtonVisibility();
|
|
66063
|
+
}
|
|
65093
66064
|
return;
|
|
65094
66065
|
}
|
|
65095
66066
|
|
|
@@ -65098,6 +66069,11 @@ function onChangeButtonSetup(
|
|
|
65098
66069
|
saveBtn.style.display = "none";
|
|
65099
66070
|
submitBtn.style.display = "";
|
|
65100
66071
|
submitBtn.disabled = !hasAnyValue;
|
|
66072
|
+
|
|
66073
|
+
// Check if More button should be visible based on dropdown content
|
|
66074
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
66075
|
+
window.checkMoreButtonVisibility();
|
|
66076
|
+
}
|
|
65101
66077
|
}
|
|
65102
66078
|
|
|
65103
66079
|
// Main form loader
|
|
@@ -65122,7 +66098,22 @@ async function loadRNform(
|
|
|
65122
66098
|
|
|
65123
66099
|
// document.getElementById("formio-cmt").innerHTML = "";
|
|
65124
66100
|
|
|
65125
|
-
Formio
|
|
66101
|
+
// Formio should already be loaded by index.js
|
|
66102
|
+
if (typeof Formio === "undefined") {
|
|
66103
|
+
console.error("\u274C Formio library not loaded");
|
|
66104
|
+
sendEventCallback({
|
|
66105
|
+
type: "ERROR",
|
|
66106
|
+
errorMessage: "ErrorCode : 016, Formio library not loaded",
|
|
66107
|
+
data: { reason: "Formio library not loaded" },
|
|
66108
|
+
});
|
|
66109
|
+
return;
|
|
66110
|
+
}
|
|
66111
|
+
|
|
66112
|
+
if (window.semantic) {
|
|
66113
|
+
Formio.use(window.semantic.default || window.semantic);
|
|
66114
|
+
} else {
|
|
66115
|
+
console.warn("Semantics UI not loaded, skipping Formio.use(semantic)");
|
|
66116
|
+
}
|
|
65126
66117
|
|
|
65127
66118
|
try {
|
|
65128
66119
|
// Determine form configuration based on mode
|
|
@@ -65161,12 +66152,29 @@ async function loadRNform(
|
|
|
65161
66152
|
formConfig.viewHtml = false;
|
|
65162
66153
|
}
|
|
65163
66154
|
|
|
66155
|
+
const formElement = document.getElementById("formio");
|
|
66156
|
+
if (!formElement) {
|
|
66157
|
+
throw new Error("DOM Element #formio not found");
|
|
66158
|
+
}
|
|
66159
|
+
|
|
66160
|
+
// Sanitize template to prevent auto-submission to Form.io API
|
|
66161
|
+
if (template) {
|
|
66162
|
+
if (template.src) delete template.src;
|
|
66163
|
+
if (template.url) delete template.url;
|
|
66164
|
+
if (template.project) delete template.project;
|
|
66165
|
+
if (template.projectId) delete template.projectId;
|
|
66166
|
+
if (template.projectUrl) delete template.projectUrl;
|
|
66167
|
+
}
|
|
66168
|
+
|
|
66169
|
+
// Create form (single attempt - Formio is already loaded by index.js)
|
|
65164
66170
|
formObj = await Formio.createForm(
|
|
65165
|
-
|
|
66171
|
+
formElement,
|
|
65166
66172
|
template,
|
|
65167
66173
|
formConfig
|
|
65168
66174
|
);
|
|
65169
66175
|
|
|
66176
|
+
|
|
66177
|
+
|
|
65170
66178
|
// Store initial form data after first change event (ensures all defaults applied)
|
|
65171
66179
|
let initialDataSet = false;
|
|
65172
66180
|
formObj.on("change", () => {
|
|
@@ -65274,6 +66282,9 @@ async function loadRNform(
|
|
|
65274
66282
|
};
|
|
65275
66283
|
}
|
|
65276
66284
|
|
|
66285
|
+
// Calculate initial progress immediately
|
|
66286
|
+
executeProgressCalculation(privateExternal, permission);
|
|
66287
|
+
|
|
65277
66288
|
// Hide FormIO submit button component and wizard buttons in readOnly mode
|
|
65278
66289
|
if (mode == "readOnly") {
|
|
65279
66290
|
const submitComponents = document.querySelectorAll(
|
|
@@ -65325,12 +66336,19 @@ async function loadRNform(
|
|
|
65325
66336
|
if (fileInput) fileInput.setAttribute("accept", "*/*");
|
|
65326
66337
|
});
|
|
65327
66338
|
} catch (error) {
|
|
65328
|
-
console.error("\u274C Error creating form:", error);
|
|
66339
|
+
console.error("\u274C Error creating form (after retries):", error);
|
|
66340
|
+
|
|
66341
|
+
// Ensure loader is hidden even on error
|
|
66342
|
+
const sdkLoader = document.getElementById('sdk-form-loader');
|
|
66343
|
+
if (sdkLoader) {
|
|
66344
|
+
sdkLoader.classList.add('hidden');
|
|
66345
|
+
}
|
|
66346
|
+
|
|
65329
66347
|
sendEventCallback({
|
|
65330
66348
|
type: "ERROR",
|
|
65331
66349
|
errorMessage:
|
|
65332
|
-
"ErrorCode : 005,
|
|
65333
|
-
data: { technicalError: error },
|
|
66350
|
+
"ErrorCode : 005, Formio not rendered the forms",
|
|
66351
|
+
data: { reason: "Failed to render form after retries", technicalError: error },
|
|
65334
66352
|
});
|
|
65335
66353
|
}
|
|
65336
66354
|
}
|
|
@@ -65340,209 +66358,292 @@ let changeTimeout = null;
|
|
|
65340
66358
|
let lastDataHash = null;
|
|
65341
66359
|
let mandatoryFieldsCache = null;
|
|
65342
66360
|
|
|
65343
|
-
|
|
66361
|
+
// Build mandatory fields cache once
|
|
66362
|
+
function buildMandatoryFieldsCache() {
|
|
66363
|
+
if (mandatoryFieldsCache) return mandatoryFieldsCache;
|
|
66364
|
+
if (!formObj) return [];
|
|
66365
|
+
|
|
66366
|
+
const cache = [];
|
|
66367
|
+
// Layout components do not have input data themselves but contain children
|
|
66368
|
+
// We traverse them but keep the current path unless the component modifies it?
|
|
66369
|
+
// Actually, standard FormIO layouts don't add to data path, but containers do.
|
|
66370
|
+
|
|
66371
|
+
function cacheMandatoryFields(components, path = "") {
|
|
66372
|
+
if (!Array.isArray(components)) return;
|
|
66373
|
+
components.forEach((comp) => {
|
|
66374
|
+
// 'comp' should be the Component Instance here
|
|
66375
|
+
if (!comp) return;
|
|
66376
|
+
|
|
66377
|
+
// The schema is usually in comp.component, but fallback to comp if it's already a schema (shouldn't be if traversing instances)
|
|
66378
|
+
const schema = comp.component || comp;
|
|
66379
|
+
|
|
66380
|
+
let fieldPath = path;
|
|
66381
|
+
|
|
66382
|
+
// List of components that are "Passthrough" for data path (Layouts)
|
|
66383
|
+
const isLayout = [
|
|
66384
|
+
"columns", "panel", "fieldset", "well", "table", "tabs", "content", "htmlelement"
|
|
66385
|
+
].includes(schema.type);
|
|
66386
|
+
|
|
66387
|
+
// Determine path
|
|
66388
|
+
if (!isLayout) {
|
|
66389
|
+
fieldPath = path ? \`\${path}.\${schema.key}\` : schema.key;
|
|
66390
|
+
}
|
|
66391
|
+
|
|
66392
|
+
const inputTypes = [
|
|
66393
|
+
"textfield", "textarea", "number", "checkbox", "radio", "select", "selectboxes",
|
|
66394
|
+
"email", "url", "day", "datetime", "file", "datamap", "tree", "survey",
|
|
66395
|
+
"signature", "datagrid", "editgrid", "container"
|
|
66396
|
+
];
|
|
66397
|
+
|
|
66398
|
+
// CACHE IF REQUIRED
|
|
66399
|
+
if (
|
|
66400
|
+
inputTypes.includes(schema.type) &&
|
|
66401
|
+
schema.validate?.required
|
|
66402
|
+
) {
|
|
66403
|
+
cache.push({
|
|
66404
|
+
key: schema.key,
|
|
66405
|
+
type: schema.type,
|
|
66406
|
+
path: fieldPath,
|
|
66407
|
+
comp: schema, // The static schema
|
|
66408
|
+
instance: comp, // The runtime component instance (has .visible, .checkCondition)
|
|
66409
|
+
});
|
|
66410
|
+
}
|
|
66411
|
+
|
|
66412
|
+
// RECURSION
|
|
66413
|
+
// We must recurse on the INSTANCE'S components to keep getting instances.
|
|
66414
|
+
// 'comp.components' is the array of child instances on a Container/Panel/etc.
|
|
66415
|
+
// 'comp.columns' is for Columns component, but each col has .components
|
|
66416
|
+
|
|
66417
|
+
// Standard container-like components (Panel, Container, etc.)
|
|
66418
|
+
if (Array.isArray(comp.components)) {
|
|
66419
|
+
cacheMandatoryFields(comp.components, fieldPath);
|
|
66420
|
+
}
|
|
66421
|
+
|
|
66422
|
+
// Columns component handles children differently in instances?
|
|
66423
|
+
// Usually comp.columns is an array of objects which contain .components (instances)
|
|
66424
|
+
if (Array.isArray(comp.columns)) {
|
|
66425
|
+
comp.columns.forEach((col) => {
|
|
66426
|
+
if (Array.isArray(col.components)) {
|
|
66427
|
+
cacheMandatoryFields(col.components, fieldPath);
|
|
66428
|
+
}
|
|
66429
|
+
});
|
|
66430
|
+
}
|
|
66431
|
+
|
|
66432
|
+
// DataGrid/EditGrid rows are generated dynamically.
|
|
66433
|
+
// The \`comp\` instance might have \`rows\` property?
|
|
66434
|
+
// Actually for DataGrid, we iterate the data rows in 'execute', not the components here.
|
|
66435
|
+
// BUT if the DataGrid has static \`components\` (the column definitions), we might need to check them?
|
|
66436
|
+
// The schema has .components (the columns).
|
|
66437
|
+
// The instance has .components (the flattened list of all cell components across all rows? Or just the column patterns?)
|
|
66438
|
+
// For progress calc, we handled DataGrid specifically in \`isFilled\` or by flattening.
|
|
66439
|
+
// If we want to support required fields INSIDE a datagrid row, we need to handle that.
|
|
66440
|
+
// Current logic: We treat DataGrid as a single "filled" item if it has rows.
|
|
66441
|
+
// We do NOT currently check if fields INSIDE the row are filled if the datagrid itself is "filled".
|
|
66442
|
+
// Users issue implies specific internal fields.
|
|
66443
|
+
|
|
66444
|
+
// NOTE: User's reported "Total mandatory: 23" suggests individual fields are counted.
|
|
66445
|
+
// If \`comp.components\` exists on a DataGrid instance, it usually holds the column definitions as components.
|
|
66446
|
+
// Let's stick to standard recursion for now.
|
|
66447
|
+
});
|
|
66448
|
+
}
|
|
66449
|
+
|
|
66450
|
+
cacheMandatoryFields(formObj.components);
|
|
66451
|
+
mandatoryFieldsCache = cache;
|
|
66452
|
+
return cache;
|
|
66453
|
+
}
|
|
66454
|
+
|
|
66455
|
+
function executeProgressCalculation(privateExternal, permission) {
|
|
65344
66456
|
if (!formObj) return;
|
|
65345
66457
|
|
|
65346
|
-
|
|
65347
|
-
|
|
65348
|
-
if (mandatoryFieldsCache) return mandatoryFieldsCache;
|
|
65349
|
-
|
|
65350
|
-
const cache = [];
|
|
65351
|
-
|
|
65352
|
-
function cacheMandatoryFields(components, path = "") {
|
|
65353
|
-
components.forEach((comp) => {
|
|
65354
|
-
if (!comp) return;
|
|
65355
|
-
const actualComp = comp.component || comp;
|
|
65356
|
-
const fieldPath = path ? \`\${path}.\${actualComp.key}\` : actualComp.key;
|
|
65357
|
-
|
|
65358
|
-
const inputTypes = [
|
|
65359
|
-
"textfield",
|
|
65360
|
-
"textarea",
|
|
65361
|
-
"number",
|
|
65362
|
-
"checkbox",
|
|
65363
|
-
"radio",
|
|
65364
|
-
"select",
|
|
65365
|
-
"selectboxes",
|
|
65366
|
-
"email",
|
|
65367
|
-
"url",
|
|
65368
|
-
"day",
|
|
65369
|
-
"datetime",
|
|
65370
|
-
"file",
|
|
65371
|
-
"datamap",
|
|
65372
|
-
"tree",
|
|
65373
|
-
"survey",
|
|
65374
|
-
"signature",
|
|
65375
|
-
];
|
|
66458
|
+
const data = formObj.data || {};
|
|
66459
|
+
const dataHash = JSON.stringify(data);
|
|
65376
66460
|
|
|
65377
|
-
|
|
65378
|
-
|
|
65379
|
-
actualComp.validate?.required
|
|
65380
|
-
) {
|
|
65381
|
-
cache.push({
|
|
65382
|
-
key: actualComp.key,
|
|
65383
|
-
type: actualComp.type,
|
|
65384
|
-
path: fieldPath,
|
|
65385
|
-
comp: actualComp,
|
|
65386
|
-
});
|
|
65387
|
-
}
|
|
66461
|
+
if (dataHash === lastDataHash) return;
|
|
66462
|
+
lastDataHash = dataHash;
|
|
65388
66463
|
|
|
65389
|
-
|
|
65390
|
-
|
|
65391
|
-
|
|
65392
|
-
|
|
65393
|
-
|
|
65394
|
-
|
|
65395
|
-
|
|
65396
|
-
|
|
65397
|
-
|
|
65398
|
-
|
|
66464
|
+
const mandatoryFields = buildMandatoryFieldsCache();
|
|
66465
|
+
let mandatory = mandatoryFields.length;
|
|
66466
|
+
let filledMandatory = 0;
|
|
66467
|
+
|
|
66468
|
+
function isFilled(comp, value) {
|
|
66469
|
+
if (Array.isArray(value)) {
|
|
66470
|
+
// Logic for array values (files, datagrid rows, etc.)
|
|
66471
|
+
const arrayNativeTypes = ['file', 'datagrid', 'editgrid', 'datamap', 'selectboxes'];
|
|
66472
|
+
const isNativeArray = arrayNativeTypes.includes(comp.type) || comp.multiple;
|
|
66473
|
+
|
|
66474
|
+
if (!isNativeArray) {
|
|
66475
|
+
// Assume row-values from extracted path -> all must range
|
|
66476
|
+
return value.length > 0 && value.every(v => isFilled(comp, v));
|
|
66477
|
+
}
|
|
66478
|
+
|
|
66479
|
+
if (comp.type === 'file' && value.length > 0 && Array.isArray(value[0])) {
|
|
66480
|
+
// File inside datagrid?
|
|
66481
|
+
return value.every(v => isFilled(comp, v));
|
|
66482
|
+
}
|
|
66483
|
+
}
|
|
66484
|
+
|
|
66485
|
+
switch (comp.type) {
|
|
66486
|
+
case "selectboxes":
|
|
66487
|
+
return Object.values(value || {}).some(Boolean);
|
|
66488
|
+
case "datamap":
|
|
66489
|
+
case "tree":
|
|
66490
|
+
return value && Object.keys(value).length > 0;
|
|
66491
|
+
case "survey":
|
|
66492
|
+
// Check if all questions in the survey are answered
|
|
66493
|
+
if (comp.questions && Array.isArray(comp.questions)) {
|
|
66494
|
+
return value && Object.keys(value).length >= comp.questions.length;
|
|
65399
66495
|
}
|
|
65400
|
-
|
|
65401
|
-
|
|
65402
|
-
|
|
65403
|
-
|
|
65404
|
-
|
|
65405
|
-
|
|
65406
|
-
|
|
65407
|
-
|
|
65408
|
-
|
|
65409
|
-
|
|
66496
|
+
return value && Object.keys(value).length > 0;
|
|
66497
|
+
case "file":
|
|
66498
|
+
return Array.isArray(value) && value.length > 0;
|
|
66499
|
+
case "checkbox":
|
|
66500
|
+
return value === true;
|
|
66501
|
+
case "editgrid":
|
|
66502
|
+
case "datagrid":
|
|
66503
|
+
return Array.isArray(value) && value.length > 0;
|
|
66504
|
+
case "signature":
|
|
66505
|
+
return !!value;
|
|
66506
|
+
default:
|
|
66507
|
+
return value !== undefined && value !== null && value !== "";
|
|
66508
|
+
}
|
|
66509
|
+
}
|
|
66510
|
+
|
|
66511
|
+
const activeMandatoryFields = [];
|
|
66512
|
+
|
|
66513
|
+
mandatoryFields.forEach((entry) => {
|
|
66514
|
+
// Check conditional visibility using Formio's checkCondition if available, or fallback to visible property
|
|
66515
|
+
// If a component is conditionally hidden, it should not count as mandatory
|
|
66516
|
+
let isVisible = true;
|
|
66517
|
+
if (entry.instance) {
|
|
66518
|
+
// Preferred: usage of Formio's internal checkCondition if accessible
|
|
66519
|
+
// But often checking .visible on the instance is sufficient as Formio updates it
|
|
66520
|
+
if (entry.instance.visible === false) isVisible = false;
|
|
66521
|
+
|
|
66522
|
+
// Double check with checkCondition if available to be sure about complex conditions
|
|
66523
|
+
if (isVisible && typeof entry.instance.checkCondition === 'function') {
|
|
66524
|
+
if (!entry.instance.checkCondition(null, data)) {
|
|
66525
|
+
isVisible = false;
|
|
65410
66526
|
}
|
|
65411
|
-
}
|
|
66527
|
+
}
|
|
65412
66528
|
}
|
|
65413
66529
|
|
|
65414
|
-
|
|
65415
|
-
|
|
65416
|
-
|
|
66530
|
+
if (!isVisible) return;
|
|
66531
|
+
|
|
66532
|
+
// Check if parent is visible (basic check, could be recursive but starting here)
|
|
66533
|
+
if (entry.instance && entry.instance.parent && entry.instance.parent.visible === false) return;
|
|
66534
|
+
|
|
66535
|
+
activeMandatoryFields.push(entry);
|
|
66536
|
+
});
|
|
66537
|
+
|
|
66538
|
+
mandatory = activeMandatoryFields.length;
|
|
66539
|
+
filledMandatory = 0;
|
|
66540
|
+
|
|
66541
|
+
activeMandatoryFields.forEach(({ key, type, path, comp }) => {
|
|
66542
|
+
let value = getValueFromData(data, path);
|
|
66543
|
+
const filled = isFilled(comp, value);
|
|
66544
|
+
if (filled) filledMandatory++;
|
|
66545
|
+
});
|
|
66546
|
+
|
|
66547
|
+
console.log("\u2705 Total mandatory fields:", mandatory);
|
|
66548
|
+
console.log("\u2705 Filled mandatory fields:", filledMandatory);
|
|
66549
|
+
const completion =
|
|
66550
|
+
mandatory === 0 ? 100 : Math.round((filledMandatory / mandatory) * 100);
|
|
66551
|
+
calculationPercentage = completion; // Update global
|
|
66552
|
+
completeFlag = completion >= 100; // Update global
|
|
66553
|
+
|
|
66554
|
+
console.log("\u{1F4CA} Completion %:", completion);
|
|
66555
|
+
|
|
66556
|
+
onChangeButtonSetup(
|
|
66557
|
+
completion,
|
|
66558
|
+
formObj.data,
|
|
66559
|
+
privateExternal,
|
|
66560
|
+
permission
|
|
66561
|
+
);
|
|
66562
|
+
|
|
66563
|
+
// Update progress bar
|
|
66564
|
+
const progressBar = document.getElementById("progress-bar");
|
|
66565
|
+
if (progressBar) {
|
|
66566
|
+
const bar = progressBar.querySelector(".progress");
|
|
66567
|
+
const badge = progressBar.querySelector(".badge");
|
|
66568
|
+
|
|
66569
|
+
bar.style.width = \`\${completion}%\`;
|
|
66570
|
+
badge.textContent = \`\${completion}%\`;
|
|
66571
|
+
|
|
66572
|
+
let left = completion;
|
|
66573
|
+
if (completion <= 0) {
|
|
66574
|
+
left = 0.5;
|
|
66575
|
+
bar.style.width = \`\${0.5}%\`;
|
|
66576
|
+
if (window.innerWidth > 768) badge.style.transform = "translateX(2%)";
|
|
66577
|
+
else if (window.innerWidth > 480) badge.style.transform = "translateX(2%)";
|
|
66578
|
+
else badge.style.transform = "translateX(1%)";
|
|
66579
|
+
} else if (completion >= 100) {
|
|
66580
|
+
left = 99.5;
|
|
66581
|
+
if (window.innerWidth > 768) badge.style.transform = "translateX(-65%)";
|
|
66582
|
+
else if (window.innerWidth > 480) badge.style.transform = "translateX(-85%)";
|
|
66583
|
+
else badge.style.transform = "translateX(-105%)";
|
|
66584
|
+
} else {
|
|
66585
|
+
// Reset transform if not edge case
|
|
66586
|
+
badge.style.transform = "translateX(-50%)"; // Standard centering, though original didn't have this explicitly in else
|
|
66587
|
+
}
|
|
66588
|
+
badge.style.left = \`\${left - 0.25}%\`;
|
|
65417
66589
|
}
|
|
66590
|
+
}
|
|
65418
66591
|
|
|
65419
|
-
|
|
65420
|
-
|
|
65421
|
-
|
|
65422
|
-
|
|
66592
|
+
|
|
66593
|
+
// Helper to safely get value from data using path strings, handling arrays (datagrids)
|
|
66594
|
+
function getValueFromData(data, path) {
|
|
66595
|
+
if (data === undefined || data === null || !path) return undefined;
|
|
66596
|
+
|
|
66597
|
+
// If path has no dots, it's a direct key
|
|
66598
|
+
if (path.indexOf('.') === -1) {
|
|
66599
|
+
// Special handling: if data is array, map it (unless path is purely index, but here assuming keys)
|
|
66600
|
+
if (Array.isArray(data)) {
|
|
66601
|
+
return data.map(item => item[path]);
|
|
65423
66602
|
}
|
|
66603
|
+
return data[path];
|
|
66604
|
+
}
|
|
65424
66605
|
|
|
65425
|
-
|
|
65426
|
-
|
|
65427
|
-
const data = submission?.data || formObj.data || {};
|
|
65428
|
-
const dataHash = JSON.stringify(data);
|
|
65429
|
-
|
|
65430
|
-
// Skip if data hasn't actually changed
|
|
65431
|
-
if (dataHash === lastDataHash) return;
|
|
65432
|
-
lastDataHash = dataHash;
|
|
65433
|
-
|
|
65434
|
-
const mandatoryFields = buildMandatoryFieldsCache();
|
|
65435
|
-
let mandatory = mandatoryFields.length;
|
|
65436
|
-
let filledMandatory = 0;
|
|
65437
|
-
|
|
65438
|
-
function isFilled(comp, value) {
|
|
65439
|
-
switch (comp.type) {
|
|
65440
|
-
case "selectboxes":
|
|
65441
|
-
return Object.values(value || {}).some(Boolean);
|
|
65442
|
-
case "datamap":
|
|
65443
|
-
case "tree":
|
|
65444
|
-
case "survey":
|
|
65445
|
-
return value && Object.keys(value).length > 0;
|
|
65446
|
-
case "file":
|
|
65447
|
-
return Array.isArray(value) && value.length > 0;
|
|
65448
|
-
case "checkbox":
|
|
65449
|
-
return value === true;
|
|
65450
|
-
case "editgrid":
|
|
65451
|
-
case "datagrid":
|
|
65452
|
-
return Array.isArray(value) && value.length > 0;
|
|
65453
|
-
case "signature":
|
|
65454
|
-
return !!value;
|
|
65455
|
-
default:
|
|
65456
|
-
return value !== undefined && value !== null && value !== "";
|
|
65457
|
-
}
|
|
65458
|
-
}
|
|
66606
|
+
const keys = path.split(".");
|
|
66607
|
+
let current = data;
|
|
65459
66608
|
|
|
65460
|
-
|
|
65461
|
-
|
|
65462
|
-
|
|
65463
|
-
try {
|
|
65464
|
-
const formComp = formObj.getComponent(key);
|
|
65465
|
-
value =
|
|
65466
|
-
formComp && typeof formComp.getValue === "function"
|
|
65467
|
-
? formComp.getValue()
|
|
65468
|
-
: data[key];
|
|
65469
|
-
} catch (e) {
|
|
65470
|
-
value = data[key];
|
|
65471
|
-
}
|
|
66609
|
+
for (let i = 0; i < keys.length; i++) {
|
|
66610
|
+
const key = keys[i];
|
|
66611
|
+
if (current === undefined || current === null) return undefined;
|
|
65472
66612
|
|
|
65473
|
-
|
|
65474
|
-
|
|
66613
|
+
if (Array.isArray(current)) {
|
|
66614
|
+
// We hit an array (e.g. datagrid rows), but we have more keys to traverse.
|
|
66615
|
+
// We must map the rest of the path over each item in the array.
|
|
66616
|
+
const remainingPath = keys.slice(i).join(".");
|
|
66617
|
+
return current.map(item => getValueFromData(item, remainingPath));
|
|
66618
|
+
}
|
|
65475
66619
|
|
|
65476
|
-
|
|
65477
|
-
|
|
65478
|
-
|
|
65479
|
-
|
|
65480
|
-
filled
|
|
65481
|
-
);
|
|
65482
|
-
});
|
|
66620
|
+
current = current[key];
|
|
66621
|
+
}
|
|
66622
|
+
return current;
|
|
66623
|
+
}
|
|
65483
66624
|
|
|
65484
|
-
|
|
65485
|
-
|
|
65486
|
-
const completion =
|
|
65487
|
-
mandatory === 0 ? 100 : Math.round((filledMandatory / mandatory) * 100);
|
|
65488
|
-
console.log("\u{1F4CA} Completion %:", completion);
|
|
65489
|
-
|
|
65490
|
-
onChangeButtonSetup(
|
|
65491
|
-
completion,
|
|
65492
|
-
formObj.data,
|
|
65493
|
-
privateExternal,
|
|
65494
|
-
permission
|
|
65495
|
-
);
|
|
66625
|
+
function setupOnChange(privateExternal, permission) {
|
|
66626
|
+
if (!formObj) return;
|
|
65496
66627
|
|
|
65497
|
-
|
|
65498
|
-
|
|
65499
|
-
|
|
65500
|
-
|
|
65501
|
-
|
|
65502
|
-
|
|
65503
|
-
// Set bar width
|
|
65504
|
-
bar.style.width = \`\${completion}%\`;
|
|
65505
|
-
|
|
65506
|
-
// Update badge text
|
|
65507
|
-
badge.textContent = \`\${completion}%\`;
|
|
65508
|
-
|
|
65509
|
-
// Calculate badge left relative to container
|
|
65510
|
-
let left = completion;
|
|
65511
|
-
|
|
65512
|
-
// Edge cases: keep badge inside screen
|
|
65513
|
-
if (completion <= 0) {
|
|
65514
|
-
left = 0.5; // slightly inside
|
|
65515
|
-
bar.style.width = \`\${0.5}%\`;
|
|
65516
|
-
if (window.innerWidth > 768) {
|
|
65517
|
-
badge.style.transform = "translateX(2%)"; // desktop
|
|
65518
|
-
} else if (window.innerWidth > 480) {
|
|
65519
|
-
badge.style.transform = "translateX(2%)"; // tablet
|
|
65520
|
-
} else if (window.innerWidth > 360) {
|
|
65521
|
-
badge.style.transform = "translateX(2%)"; // mobile
|
|
65522
|
-
} else {
|
|
65523
|
-
badge.style.transform = "translateX(1%)"; // very small phone
|
|
65524
|
-
}
|
|
65525
|
-
}
|
|
65526
|
-
if (completion >= 100) {
|
|
65527
|
-
left = 99.5; // slightly inside
|
|
65528
|
-
// Responsive translateX for different screen widths
|
|
65529
|
-
if (window.innerWidth > 768) {
|
|
65530
|
-
badge.style.transform = "translateX(-65%)"; // desktop
|
|
65531
|
-
} else if (window.innerWidth > 480) {
|
|
65532
|
-
badge.style.transform = "translateX(-85%)"; // tablet
|
|
65533
|
-
} else if (window.innerWidth > 360) {
|
|
65534
|
-
badge.style.transform = "translateX(-95%)"; // mobile
|
|
65535
|
-
} else {
|
|
65536
|
-
badge.style.transform = "translateX(-105%)"; // very small phone
|
|
65537
|
-
}
|
|
65538
|
-
}
|
|
66628
|
+
formObj.on("change", (event) => {
|
|
66629
|
+
// Blur datetime components on change to close the native keyboard/picker
|
|
66630
|
+
if (event.changed?.component?.type === "datetime") {
|
|
66631
|
+
document.activeElement.blur();
|
|
66632
|
+
}
|
|
65539
66633
|
|
|
65540
|
-
|
|
65541
|
-
|
|
66634
|
+
// Clear existing timeout
|
|
66635
|
+
if (changeTimeout) {
|
|
66636
|
+
clearTimeout(changeTimeout);
|
|
66637
|
+
}
|
|
66638
|
+
|
|
66639
|
+
// Invalidate cache to ensure conditional visibility updates are captured
|
|
66640
|
+
mandatoryFieldsCache = null;
|
|
66641
|
+
|
|
66642
|
+
// Debounce the change handler
|
|
66643
|
+
changeTimeout = setTimeout(() => {
|
|
66644
|
+
executeProgressCalculation(privateExternal, permission);
|
|
65542
66645
|
}, 300); // 300ms debounce delay
|
|
65543
66646
|
});
|
|
65544
|
-
|
|
65545
|
-
// removed ad-hoc setTimeout: rely on formObj.formReady and LessRenderingComplete events
|
|
65546
66647
|
}
|
|
65547
66648
|
|
|
65548
66649
|
// Function to convert file objects back to IDs
|
|
@@ -65603,6 +66704,27 @@ function FormOnSubmit() {
|
|
|
65603
66704
|
attachmentfileKeysSDK
|
|
65604
66705
|
);
|
|
65605
66706
|
|
|
66707
|
+
// Check strict completion requirement
|
|
66708
|
+
const requireComplete =
|
|
66709
|
+
window.__unviredFormsOptions?.requireCompleteForm === true ||
|
|
66710
|
+
window.__unviredFormsOptions?.requireCompleteForm === "true";
|
|
66711
|
+
|
|
66712
|
+
if (!requireComplete) {
|
|
66713
|
+
// Bypass validation and submit immediately
|
|
66714
|
+
sendEventCallback({
|
|
66715
|
+
type: FORM_EVENTS.SUBMIT,
|
|
66716
|
+
message: "Success: Form submitted successfully (Validation Bypassed).",
|
|
66717
|
+
data: {
|
|
66718
|
+
formData: processedData,
|
|
66719
|
+
completeFlag,
|
|
66720
|
+
completionPercentage: calculationPercentage,
|
|
66721
|
+
commentsData: FORM_COMMENTS_DATA,
|
|
66722
|
+
result: processedData,
|
|
66723
|
+
},
|
|
66724
|
+
});
|
|
66725
|
+
return;
|
|
66726
|
+
}
|
|
66727
|
+
|
|
65606
66728
|
formObj
|
|
65607
66729
|
.submit()
|
|
65608
66730
|
.then((result) => {
|
|
@@ -65620,7 +66742,19 @@ function FormOnSubmit() {
|
|
|
65620
66742
|
})
|
|
65621
66743
|
.catch((error) => {
|
|
65622
66744
|
console.error(error);
|
|
65623
|
-
|
|
66745
|
+
const errorMsg = (error && error.message) ? error.message : "Please check the form for errors.";
|
|
66746
|
+
showDynamicModal("Error", [{ label: "OK" }], errorMsg);
|
|
66747
|
+
sendEventCallback({
|
|
66748
|
+
type: FORM_EVENTS.SUBMIT_ERROR,
|
|
66749
|
+
errorMessage: "ErrorCode : 006, Formio not submit the form",
|
|
66750
|
+
data: {
|
|
66751
|
+
reason: "Form submission failed",
|
|
66752
|
+
formData: processedData,
|
|
66753
|
+
completeFlag,
|
|
66754
|
+
completionPercentage: calculationPercentage,
|
|
66755
|
+
technicalError: error,
|
|
66756
|
+
},
|
|
66757
|
+
});
|
|
65624
66758
|
});
|
|
65625
66759
|
}
|
|
65626
66760
|
|
|
@@ -65652,9 +66786,7 @@ async function loadComments() {
|
|
|
65652
66786
|
window.FORM_VOB_ARR,
|
|
65653
66787
|
window.FORM_USERS_LIST || []
|
|
65654
66788
|
);
|
|
65655
|
-
|
|
65656
|
-
showCommentsView();
|
|
65657
|
-
}, 500);
|
|
66789
|
+
showCommentsView();
|
|
65658
66790
|
} else {
|
|
65659
66791
|
console.error("loadCommentsform is not a function");
|
|
65660
66792
|
}
|
|
@@ -65666,6 +66798,22 @@ async function loadComments() {
|
|
|
65666
66798
|
function FormOnSave() {
|
|
65667
66799
|
if (!formObj) return;
|
|
65668
66800
|
|
|
66801
|
+
const formData = formObj.getValue().data;
|
|
66802
|
+
const hasAnyValue = Object.values(formData || {}).some(
|
|
66803
|
+
(v) =>
|
|
66804
|
+
v !== undefined &&
|
|
66805
|
+
v !== null &&
|
|
66806
|
+
v !== "" &&
|
|
66807
|
+
v !== false &&
|
|
66808
|
+
!(Array.isArray(v) && v.length === 0) &&
|
|
66809
|
+
!(typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0)
|
|
66810
|
+
);
|
|
66811
|
+
|
|
66812
|
+
if (!hasAnyValue) {
|
|
66813
|
+
showDynamicModal("Attention", [{ label: "OK" }], "Please fill at least one field before saving.");
|
|
66814
|
+
return;
|
|
66815
|
+
}
|
|
66816
|
+
|
|
65669
66817
|
showDynamicModal("Do you want to save the data?", [
|
|
65670
66818
|
{
|
|
65671
66819
|
label: "Yes",
|
|
@@ -65682,7 +66830,6 @@ function FormOnSave() {
|
|
|
65682
66830
|
completionPercentage: calculationPercentage,
|
|
65683
66831
|
},
|
|
65684
66832
|
});
|
|
65685
|
-
FormOnBackNavigation();
|
|
65686
66833
|
},
|
|
65687
66834
|
},
|
|
65688
66835
|
{
|
|
@@ -65726,6 +66873,58 @@ function setImageData(imageData, id, fileName) {
|
|
|
65726
66873
|
}
|
|
65727
66874
|
|
|
65728
66875
|
// ============================================ MODAL ===========================================================
|
|
66876
|
+
// Function to check if More dropdown has any visible items
|
|
66877
|
+
window.checkMoreButtonVisibility = function () {
|
|
66878
|
+
const moreBtn = document.getElementById("unvired-more-btn");
|
|
66879
|
+
|
|
66880
|
+
// Safety check: if button doesn't exist, we can't do anything
|
|
66881
|
+
if (!moreBtn) return;
|
|
66882
|
+
|
|
66883
|
+
const options = window.__unviredFormsOptions || {};
|
|
66884
|
+
|
|
66885
|
+
// If showMoreButton is explicitly false (from options), force hide
|
|
66886
|
+
if (options.showMoreButton === false) {
|
|
66887
|
+
moreBtn.style.display = "none";
|
|
66888
|
+
return;
|
|
66889
|
+
}
|
|
66890
|
+
|
|
66891
|
+
// Get all menu items in the dropdown
|
|
66892
|
+
const completeOption = document.getElementById("completeOption");
|
|
66893
|
+
const saveOption = document.getElementById("saveOption");
|
|
66894
|
+
const documentsOption = document.getElementById("documentsOption");
|
|
66895
|
+
const commentsItem = document.getElementById("comments-item");
|
|
66896
|
+
const helpItem = document.getElementById("help-item");
|
|
66897
|
+
|
|
66898
|
+
// Check visibility logic:
|
|
66899
|
+
// 1. Is the item actually displayed (style.display !== 'none')?
|
|
66900
|
+
// 2. Is the item allowed by options (e.g. showComments, showHelp)?
|
|
66901
|
+
// For completeOption/saveOption, their display is managed by logic.
|
|
66902
|
+
// For documentsOption, its display is managed by logic.
|
|
66903
|
+
// For comments/help, they are often just static items toggled.
|
|
66904
|
+
|
|
66905
|
+
const isVisible = (el) => el && el.style.display !== "none";
|
|
66906
|
+
|
|
66907
|
+
// Assuming options.showComments/Help also imply the item SHOULD be visible if logic permits
|
|
66908
|
+
// But logic might hide them. The 'isVisible' check handles dynamic logic.
|
|
66909
|
+
// But for comments/help, they might be hidden initially.
|
|
66910
|
+
|
|
66911
|
+
const hasVisibleItems =
|
|
66912
|
+
isVisible(completeOption) ||
|
|
66913
|
+
isVisible(saveOption) ||
|
|
66914
|
+
isVisible(documentsOption) ||
|
|
66915
|
+
isVisible(commentsItem) ||
|
|
66916
|
+
isVisible(helpItem); // Simplified: check actual DOM state
|
|
66917
|
+
|
|
66918
|
+
// If ANY item is visible, show the button. Otherwise hide.
|
|
66919
|
+
if (hasVisibleItems) {
|
|
66920
|
+
moreBtn.style.display = "";
|
|
66921
|
+
} else {
|
|
66922
|
+
moreBtn.style.display = "none";
|
|
66923
|
+
}
|
|
66924
|
+
};
|
|
66925
|
+
|
|
66926
|
+
window.checkMoreButtonVisibility();
|
|
66927
|
+
|
|
65729
66928
|
window.loadComments = loadComments;
|
|
65730
66929
|
window.loadRNform = loadRNform;
|
|
65731
66930
|
window.FormOnSave = FormOnSave;
|
|
@@ -65734,6 +66933,9 @@ window.setImageData = setImageData;
|
|
|
65734
66933
|
window.FormOnSubmit = FormOnSubmit;
|
|
65735
66934
|
window.resetFormCache = resetFormCache;
|
|
65736
66935
|
|
|
66936
|
+
// Notify that loadRNform is ready (for event-based coordination)
|
|
66937
|
+
document.dispatchEvent(new CustomEvent('LoadRNformReady'));
|
|
66938
|
+
|
|
65737
66939
|
})();
|
|
65738
66940
|
|
|
65739
66941
|
// === SCRIPT_SEPARATOR ===
|
|
@@ -65789,7 +66991,7 @@ async function loadCommentsform(
|
|
|
65789
66991
|
window.formObj.nosubmit = true;
|
|
65790
66992
|
|
|
65791
66993
|
// Listen to form changes (optional, currently empty)
|
|
65792
|
-
window.formObj.on("change", () => {});
|
|
66994
|
+
window.formObj.on("change", () => { });
|
|
65793
66995
|
|
|
65794
66996
|
// Initialize Recogito and store globally
|
|
65795
66997
|
window.commentsResponse = Recogito.init({
|
|
@@ -65813,8 +67015,8 @@ async function loadCommentsform(
|
|
|
65813
67015
|
});
|
|
65814
67016
|
|
|
65815
67017
|
// Event listeners
|
|
65816
|
-
window.commentsResponse.on("createAnnotation", function (annotation) {});
|
|
65817
|
-
window.commentsResponse.on("updateAnnotation", function (annotation) {});
|
|
67018
|
+
window.commentsResponse.on("createAnnotation", function (annotation) { });
|
|
67019
|
+
window.commentsResponse.on("updateAnnotation", function (annotation) { });
|
|
65818
67020
|
window.commentsResponse.on("selectAnnotation", function (annotation) {
|
|
65819
67021
|
const eventCustom = new CustomEvent("annotateCss", { detail: true });
|
|
65820
67022
|
document.dispatchEvent(eventCustom);
|
|
@@ -65865,6 +67067,13 @@ async function goToformRender() {
|
|
|
65865
67067
|
}
|
|
65866
67068
|
} catch (e) {
|
|
65867
67069
|
console.error("Error reloading form:", e);
|
|
67070
|
+
if (typeof sendEventCallback === 'function') {
|
|
67071
|
+
sendEventCallback({
|
|
67072
|
+
type: "ERROR",
|
|
67073
|
+
errorMessage: "ErrorCode : 005, Formio not rendered the forms",
|
|
67074
|
+
data: { reason: "Failed to reload forms", technicalError: e }
|
|
67075
|
+
});
|
|
67076
|
+
}
|
|
65868
67077
|
}
|
|
65869
67078
|
} else {
|
|
65870
67079
|
console.error("loadRNform is not defined");
|
|
@@ -65937,71 +67146,118 @@ window.CommentOnBack = CommentOnBack;
|
|
|
65937
67146
|
|
|
65938
67147
|
// Click outside handler for tooltip
|
|
65939
67148
|
document.addEventListener('click', function (event) {
|
|
65940
|
-
const moreBtn = document.getElementById('
|
|
67149
|
+
const moreBtn = document.getElementById('unvired-more-btn');
|
|
65941
67150
|
const tooltip = document.getElementById('moreTooltip');
|
|
65942
67151
|
if (moreBtn && tooltip && !moreBtn.contains(event.target) && !tooltip.contains(event.target)) {
|
|
65943
67152
|
tooltip.style.display = 'none';
|
|
65944
67153
|
}
|
|
65945
67154
|
});
|
|
65946
|
-
`.split(
|
|
65947
|
-
|
|
65948
|
-
|
|
65949
|
-
|
|
65950
|
-
|
|
65951
|
-
|
|
65952
|
-
|
|
65953
|
-
|
|
65954
|
-
|
|
65955
|
-
|
|
65956
|
-
|
|
65957
|
-
|
|
65958
|
-
|
|
65959
|
-
|
|
65960
|
-
|
|
67155
|
+
`.split(
|
|
67156
|
+
"\n\n// === SCRIPT_SEPARATOR ===\n\n"
|
|
67157
|
+
);
|
|
67158
|
+
if (!window.__unviredSdkScriptsLoaded && !window.__unviredSdkScriptsLoading) {
|
|
67159
|
+
window.__unviredSdkScriptsLoading = true;
|
|
67160
|
+
console.log("Initializing Unvired SDK scripts...");
|
|
67161
|
+
if (scriptContents[0] && scriptContents[0].trim()) {
|
|
67162
|
+
const jqueryScript = document.createElement("script");
|
|
67163
|
+
jqueryScript.textContent = scriptContents[0];
|
|
67164
|
+
jqueryScript.setAttribute("data-unvired-script", "jquery");
|
|
67165
|
+
document.head.appendChild(jqueryScript);
|
|
67166
|
+
}
|
|
67167
|
+
if (loaderElement) {
|
|
67168
|
+
const loaderText = loaderElement.querySelector(".sdk-loader-text");
|
|
67169
|
+
if (loaderText) loaderText.textContent = "Loading Formio Library...";
|
|
67170
|
+
}
|
|
67171
|
+
try {
|
|
67172
|
+
await new Promise((resolve, reject) => {
|
|
67173
|
+
const formioScript = document.createElement("script");
|
|
67174
|
+
formioScript.src = options.formioLibPath.formioPath;
|
|
67175
|
+
formioScript.async = false;
|
|
67176
|
+
formioScript.onload = () => {
|
|
67177
|
+
if (typeof window.Formio !== "undefined") {
|
|
67178
|
+
resolve();
|
|
67179
|
+
} else {
|
|
67180
|
+
reject(new Error("Formio script loaded but window.Formio is undefined"));
|
|
67181
|
+
}
|
|
67182
|
+
};
|
|
67183
|
+
formioScript.onerror = () => {
|
|
67184
|
+
reject(new Error(`Failed to load Formio script from ${options.formioLibPath.formioPath}`));
|
|
67185
|
+
};
|
|
67186
|
+
document.head.appendChild(formioScript);
|
|
67187
|
+
});
|
|
67188
|
+
} catch (error) {
|
|
67189
|
+
window.__unviredSdkScriptsLoading = false;
|
|
67190
|
+
throw error;
|
|
67191
|
+
}
|
|
67192
|
+
for (let i = 1; i <= 2; i++) {
|
|
67193
|
+
if (scriptContents[i] && scriptContents[i].trim()) {
|
|
67194
|
+
const scriptElement = document.createElement("script");
|
|
67195
|
+
scriptElement.textContent = scriptContents[i];
|
|
67196
|
+
scriptElement.setAttribute("data-unvired-script", `recogito-${i}`);
|
|
67197
|
+
document.head.appendChild(scriptElement);
|
|
65961
67198
|
}
|
|
65962
|
-
};
|
|
65963
|
-
if (formioScript.onload !== void 0) {
|
|
65964
|
-
formioScript.onload = checkFormio;
|
|
65965
|
-
} else {
|
|
65966
|
-
checkFormio();
|
|
65967
67199
|
}
|
|
65968
|
-
|
|
65969
|
-
|
|
65970
|
-
|
|
65971
|
-
|
|
65972
|
-
|
|
65973
|
-
|
|
65974
|
-
}
|
|
65975
|
-
|
|
65976
|
-
|
|
65977
|
-
|
|
65978
|
-
|
|
65979
|
-
|
|
65980
|
-
|
|
65981
|
-
|
|
65982
|
-
|
|
65983
|
-
|
|
65984
|
-
|
|
65985
|
-
|
|
65986
|
-
|
|
65987
|
-
|
|
65988
|
-
|
|
65989
|
-
|
|
65990
|
-
|
|
65991
|
-
|
|
65992
|
-
|
|
65993
|
-
|
|
65994
|
-
|
|
65995
|
-
|
|
65996
|
-
|
|
65997
|
-
|
|
67200
|
+
if (scriptContents[3] && scriptContents[3].trim()) {
|
|
67201
|
+
const lessScript = document.createElement("script");
|
|
67202
|
+
lessScript.textContent = scriptContents[3];
|
|
67203
|
+
lessScript.setAttribute("data-unvired-script", "less");
|
|
67204
|
+
document.head.appendChild(lessScript);
|
|
67205
|
+
}
|
|
67206
|
+
window.form = window.form || {};
|
|
67207
|
+
window.platform = window.platform || {};
|
|
67208
|
+
window.ResizeObserver = window.ResizeObserver || ResizeObserver;
|
|
67209
|
+
if (typeof browserMD5File !== "undefined") {
|
|
67210
|
+
window.form.BMF = new browserMD5File();
|
|
67211
|
+
}
|
|
67212
|
+
window.less = window.less || {};
|
|
67213
|
+
if (typeof window.__Html5QrcodeLibrary__ !== "undefined") {
|
|
67214
|
+
window.html5QrCode = window.__Html5QrcodeLibrary__;
|
|
67215
|
+
}
|
|
67216
|
+
for (let i = 4; i < scriptContents.length; i++) {
|
|
67217
|
+
const scriptContent = scriptContents[i];
|
|
67218
|
+
if (scriptContent.trim()) {
|
|
67219
|
+
const scriptElement = document.createElement("script");
|
|
67220
|
+
const isModuleScript = i >= scriptContents.length - 4;
|
|
67221
|
+
if (isModuleScript) {
|
|
67222
|
+
scriptElement.type = "module";
|
|
67223
|
+
}
|
|
67224
|
+
scriptElement.textContent = scriptContent;
|
|
67225
|
+
scriptElement.setAttribute("data-unvired-script", `script-${i}`);
|
|
67226
|
+
document.head.appendChild(scriptElement);
|
|
67227
|
+
}
|
|
67228
|
+
}
|
|
67229
|
+
window.__unviredSdkScriptsLoaded = true;
|
|
67230
|
+
window.__unviredSdkScriptsLoading = false;
|
|
67231
|
+
console.log("\u2705 All Unvired SDK scripts loaded successfully");
|
|
67232
|
+
} else if (window.__unviredSdkScriptsLoading) {
|
|
67233
|
+
console.log("Scripts are being loaded by another instance, checking if already loaded...");
|
|
67234
|
+
if (!window.__unviredSdkScriptsLoaded) {
|
|
67235
|
+
console.warn("\u26A0\uFE0F Scripts marked as loading but not yet loaded - waiting...");
|
|
67236
|
+
window.__unviredSdkScriptsLoaded = true;
|
|
67237
|
+
window.__unviredSdkScriptsLoading = false;
|
|
67238
|
+
}
|
|
67239
|
+
console.log("\u2705 Scripts are available, continuing...");
|
|
67240
|
+
} else {
|
|
67241
|
+
console.log("Unvired SDK scripts already loaded, skipping injection.");
|
|
67242
|
+
if (typeof window.Formio === "undefined") {
|
|
67243
|
+
const errorMsg = `ErrorCode : 005, Formio library not available even though scripts were loaded. Path: ${options.formioLibPath.formioPath}`;
|
|
67244
|
+
console.error(errorMsg);
|
|
67245
|
+
if (loaderElement) {
|
|
67246
|
+
loaderElement.classList.add("hidden");
|
|
65998
67247
|
}
|
|
65999
|
-
|
|
66000
|
-
|
|
66001
|
-
|
|
67248
|
+
sendEventCallback2({
|
|
67249
|
+
type: "ERROR",
|
|
67250
|
+
errorMessage: errorMsg,
|
|
67251
|
+
data: {
|
|
67252
|
+
technicalError: new Error(errorMsg),
|
|
67253
|
+
formioPath: options.formioLibPath.formioPath,
|
|
67254
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
67255
|
+
}
|
|
67256
|
+
});
|
|
67257
|
+
throw new Error(errorMsg);
|
|
66002
67258
|
}
|
|
67259
|
+
console.log("\u2705 Formio verified (previously loaded)");
|
|
66003
67260
|
}
|
|
66004
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
66005
67261
|
window.FORM_TEMPLATE = mergedWithMasterData;
|
|
66006
67262
|
window.FORM_PREVIOUS_DATA = submissionData;
|
|
66007
67263
|
window.FORM_MODE = options.mode;
|
|
@@ -66013,6 +67269,7 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66013
67269
|
window.FORM_ENV = options.environmentVariable;
|
|
66014
67270
|
window.FORM_THEME_DATA = options.themeData;
|
|
66015
67271
|
window.FORM_USER_DATA = options.userData;
|
|
67272
|
+
window.FORM_USERS_LIST = options.usersList;
|
|
66016
67273
|
window.FORM_CONTROL_DATA = options.controlData;
|
|
66017
67274
|
window.FORM_PRIVATE_EXTERNAL = options.privateExternal;
|
|
66018
67275
|
window.FORM_PERMISSION = options.permission;
|
|
@@ -66027,13 +67284,18 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66027
67284
|
ONCHANGE: "FORM_ONCHANGE"
|
|
66028
67285
|
};
|
|
66029
67286
|
const backBtn = container.querySelector("#form-back-btn");
|
|
66030
|
-
const moreBtn = container.querySelector("#
|
|
67287
|
+
const moreBtn = container.querySelector("#unvired-more-btn");
|
|
66031
67288
|
if (backBtn) {
|
|
66032
67289
|
backBtn.style.display = options.showBackButton ? "inline-block" : "none";
|
|
66033
67290
|
}
|
|
66034
67291
|
if (moreBtn && !options.showMoreButton) {
|
|
66035
67292
|
moreBtn.style.display = "none";
|
|
66036
67293
|
}
|
|
67294
|
+
window.__unviredFormsOptions = options;
|
|
67295
|
+
window.checkDocumentsVisibility();
|
|
67296
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
67297
|
+
window.checkMoreButtonVisibility();
|
|
67298
|
+
}
|
|
66037
67299
|
if (options.platform === "web") {
|
|
66038
67300
|
window.platform = { isBrowser: true, isAndroid: false, iosPlatform: false };
|
|
66039
67301
|
} else if (options.platform === "android") {
|
|
@@ -66071,6 +67333,8 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66071
67333
|
if (options.language) window.FORMIO_LANGUAGE = options.language;
|
|
66072
67334
|
if (options.translations) window.FORMIO_I18N = options.translations;
|
|
66073
67335
|
if (options.userData) {
|
|
67336
|
+
window.firstName = options.userData.firstName;
|
|
67337
|
+
window.lastName = options.userData.lastName;
|
|
66074
67338
|
window.form = window.form || {};
|
|
66075
67339
|
Object.assign(window.form, options.userData);
|
|
66076
67340
|
}
|
|
@@ -66088,59 +67352,38 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66088
67352
|
sendEventCallback2
|
|
66089
67353
|
);
|
|
66090
67354
|
}
|
|
66091
|
-
|
|
66092
|
-
|
|
66093
|
-
|
|
66094
|
-
|
|
66095
|
-
|
|
66096
|
-
|
|
66097
|
-
|
|
66098
|
-
|
|
66099
|
-
|
|
66100
|
-
|
|
66101
|
-
|
|
66102
|
-
|
|
66103
|
-
|
|
66104
|
-
|
|
66105
|
-
|
|
66106
|
-
);
|
|
66107
|
-
if (loaderElement && window.formObj) {
|
|
66108
|
-
window.formObj.formReady.then(() => {
|
|
66109
|
-
if (loaderElement) {
|
|
66110
|
-
loaderElement.classList.add("hidden");
|
|
66111
|
-
setTimeout(() => {
|
|
66112
|
-
if (loaderElement && loaderElement.parentNode) {
|
|
66113
|
-
loaderElement.parentNode.removeChild(loaderElement);
|
|
66114
|
-
}
|
|
66115
|
-
}, 400);
|
|
66116
|
-
}
|
|
66117
|
-
}).catch(() => {
|
|
66118
|
-
setTimeout(() => {
|
|
66119
|
-
if (loaderElement) {
|
|
66120
|
-
loaderElement.classList.add("hidden");
|
|
66121
|
-
setTimeout(() => {
|
|
66122
|
-
if (loaderElement && loaderElement.parentNode) {
|
|
66123
|
-
loaderElement.parentNode.removeChild(loaderElement);
|
|
66124
|
-
}
|
|
66125
|
-
}, 400);
|
|
66126
|
-
}
|
|
66127
|
-
}, 2e3);
|
|
66128
|
-
});
|
|
66129
|
-
}
|
|
66130
|
-
} else if (attempts < maxAttempts) {
|
|
66131
|
-
attempts++;
|
|
66132
|
-
console.log(`Waiting for loadRNform... attempt ${attempts}`);
|
|
66133
|
-
setTimeout(waitForLoadRNform, 500);
|
|
66134
|
-
} else {
|
|
66135
|
-
console.error("window.loadRNform is not defined after waiting", {
|
|
66136
|
-
availableFunctions: Object.keys(window).filter((key) => typeof window[key] === "function")
|
|
66137
|
-
});
|
|
66138
|
-
if (loaderElement) {
|
|
66139
|
-
loaderElement.classList.add("hidden");
|
|
67355
|
+
if (loaderElement) {
|
|
67356
|
+
const loaderText = loaderElement.querySelector(".sdk-loader-text");
|
|
67357
|
+
if (loaderText) loaderText.textContent = "Initializing Form...";
|
|
67358
|
+
}
|
|
67359
|
+
if (typeof window.loadRNform !== "function") {
|
|
67360
|
+
console.log("\u23F3 loadRNform not ready yet, waiting for LoadRNformReady event...");
|
|
67361
|
+
await new Promise((resolve) => {
|
|
67362
|
+
const onReady = () => {
|
|
67363
|
+
document.removeEventListener("LoadRNformReady", onReady);
|
|
67364
|
+
console.log("\u2705 loadRNform is now ready");
|
|
67365
|
+
resolve();
|
|
67366
|
+
};
|
|
67367
|
+
document.addEventListener("LoadRNformReady", onReady);
|
|
67368
|
+
if (typeof window.loadRNform === "function") {
|
|
67369
|
+
onReady();
|
|
66140
67370
|
}
|
|
66141
|
-
}
|
|
66142
|
-
}
|
|
66143
|
-
|
|
67371
|
+
});
|
|
67372
|
+
} else {
|
|
67373
|
+
console.log("\u2705 loadRNform is already available");
|
|
67374
|
+
}
|
|
67375
|
+
await window.loadRNform(
|
|
67376
|
+
mergedWithMasterData,
|
|
67377
|
+
processedSubmissionData,
|
|
67378
|
+
options.themeData,
|
|
67379
|
+
options.mode,
|
|
67380
|
+
options.language,
|
|
67381
|
+
options.translations,
|
|
67382
|
+
options.controlData,
|
|
67383
|
+
options.privateExternal,
|
|
67384
|
+
options.permission,
|
|
67385
|
+
fileKeys
|
|
67386
|
+
);
|
|
66144
67387
|
return {
|
|
66145
67388
|
sendAction: (action) => {
|
|
66146
67389
|
var _a2;
|
|
@@ -66158,6 +67401,51 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66158
67401
|
}
|
|
66159
67402
|
};
|
|
66160
67403
|
}
|
|
67404
|
+
window.closeDocumentsModal = function() {
|
|
67405
|
+
if (typeof $ !== "undefined" && $.fn.modal) {
|
|
67406
|
+
$("#documentsModal").modal("hide");
|
|
67407
|
+
} else {
|
|
67408
|
+
const modal = document.getElementById("documentsModal");
|
|
67409
|
+
if (modal) {
|
|
67410
|
+
modal.style.display = "none";
|
|
67411
|
+
modal.classList.remove("active");
|
|
67412
|
+
}
|
|
67413
|
+
}
|
|
67414
|
+
};
|
|
67415
|
+
window.checkDocumentsVisibility = async function() {
|
|
67416
|
+
const docBtn = document.getElementById("documentsOption");
|
|
67417
|
+
const docDivider = document.getElementById("documentsDivider");
|
|
67418
|
+
const hasDocs = await hasDocuments();
|
|
67419
|
+
docBtn.style.display = hasDocs ? "block" : "none";
|
|
67420
|
+
if (docDivider) docDivider.style.display = hasDocs ? "block" : "none";
|
|
67421
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
67422
|
+
window.checkMoreButtonVisibility();
|
|
67423
|
+
}
|
|
67424
|
+
};
|
|
67425
|
+
window.insertAppDocument = async function(doc) {
|
|
67426
|
+
try {
|
|
67427
|
+
await insertDocument(doc);
|
|
67428
|
+
console.log("Document inserted");
|
|
67429
|
+
await window.checkDocumentsVisibility();
|
|
67430
|
+
return true;
|
|
67431
|
+
} catch (e) {
|
|
67432
|
+
console.error("Failed to insert document", e);
|
|
67433
|
+
return false;
|
|
67434
|
+
}
|
|
67435
|
+
};
|
|
67436
|
+
window.deleteAppDocument = async function(id) {
|
|
67437
|
+
try {
|
|
67438
|
+
await deleteDocument(id);
|
|
67439
|
+
console.log("Document deleted");
|
|
67440
|
+
await window.checkDocumentsVisibility();
|
|
67441
|
+
return true;
|
|
67442
|
+
} catch (e) {
|
|
67443
|
+
console.error("Failed to delete document", e);
|
|
67444
|
+
return false;
|
|
67445
|
+
}
|
|
67446
|
+
};
|
|
67447
|
+
window.getAllDocuments = getAllDocuments;
|
|
67448
|
+
window.hasDocuments = hasDocuments;
|
|
66161
67449
|
export {
|
|
66162
67450
|
loadUnviredForms
|
|
66163
67451
|
};
|