@unvired/turboforms-embed-sdk 1.0.11 → 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 +566 -228
- package/dist/unvired-forms-sdk.js +1839 -599
- 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,28 +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
27814
|
<div class="item" id="completeOption" onclick="FormOnSubmit()" style="display: none;">Complete</div>
|
|
27238
|
-
<div class="divider"
|
|
27815
|
+
<div class="divider"></div>
|
|
27239
27816
|
<div class="item" id="saveOption" onclick="FormOnSave()" style="display: none;">Save</div>
|
|
27240
|
-
<div class="divider"
|
|
27241
|
-
<div class="item">Documents</div>
|
|
27242
|
-
<div class="divider"
|
|
27817
|
+
<div class="divider"></div>
|
|
27818
|
+
<div class="item" id="documentsOption" onclick="openDocumentsModal()" style="display: none;">Documents</div>
|
|
27819
|
+
<div class="divider"></div>
|
|
27243
27820
|
<div class="item" id="comments-item" style="display: none;" onclick="loadComments()">Comments</div>
|
|
27244
27821
|
<div class="divider"></div>
|
|
27245
|
-
<div class="item" onclick="openHelpLink()">Help</div>
|
|
27822
|
+
<div class="item" id="help-item" style="display: none;" onclick="openHelpLink()">Help</div>
|
|
27246
27823
|
</div>
|
|
27247
27824
|
</div>
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
|
|
27251
|
-
<
|
|
27252
|
-
|
|
27253
|
-
</
|
|
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>
|
|
27254
27839
|
</div>
|
|
27255
27840
|
`;
|
|
27256
27841
|
let loaderElement = null;
|
|
@@ -27261,23 +27846,48 @@ select.ui.dropdown {
|
|
|
27261
27846
|
<div class="sdk-loader-spinner"></div>
|
|
27262
27847
|
<div class="sdk-loader-text">Loading Form...</div>
|
|
27263
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>
|
|
27264
27852
|
`;
|
|
27265
27853
|
container.appendChild(loaderElement);
|
|
27266
27854
|
}
|
|
27267
|
-
window.toggleTooltip = function() {
|
|
27855
|
+
window.toggleTooltip = function(event) {
|
|
27856
|
+
if (event) {
|
|
27857
|
+
event.stopPropagation();
|
|
27858
|
+
}
|
|
27268
27859
|
const tooltip = document.getElementById("moreTooltip");
|
|
27269
|
-
const commentsDivider = document.getElementById("comments-divider");
|
|
27270
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
|
+
}
|
|
27271
27872
|
if (tooltip.style.display === "none") {
|
|
27272
27873
|
tooltip.style.display = "flex";
|
|
27273
|
-
|
|
27274
|
-
commentsDivider.style.display = "";
|
|
27275
|
-
commentsItem.style.display = "";
|
|
27276
|
-
}, 500);
|
|
27874
|
+
tooltip.style.flexDirection = "column";
|
|
27277
27875
|
} else {
|
|
27278
27876
|
tooltip.style.display = "none";
|
|
27279
|
-
|
|
27280
|
-
|
|
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
|
+
}
|
|
27281
27891
|
}
|
|
27282
27892
|
};
|
|
27283
27893
|
window.openHelpLink = function() {
|
|
@@ -27292,36 +27902,46 @@ select.ui.dropdown {
|
|
|
27292
27902
|
}
|
|
27293
27903
|
};
|
|
27294
27904
|
document.addEventListener("click", function(event) {
|
|
27295
|
-
const moreBtn2 = document.getElementById("
|
|
27905
|
+
const moreBtn2 = document.getElementById("unvired-more-btn");
|
|
27296
27906
|
const tooltip = document.getElementById("moreTooltip");
|
|
27297
27907
|
if (moreBtn2 && tooltip && !moreBtn2.contains(event.target) && !tooltip.contains(event.target)) {
|
|
27298
27908
|
tooltip.style.display = "none";
|
|
27299
27909
|
}
|
|
27300
27910
|
});
|
|
27301
|
-
window.loadComments = function() {
|
|
27911
|
+
window.loadComments = window.loadComments || function() {
|
|
27302
27912
|
if (typeof window.loadCommentsFunction === "function") {
|
|
27303
27913
|
window.loadCommentsFunction();
|
|
27304
27914
|
}
|
|
27305
27915
|
};
|
|
27306
|
-
window.FormOnBack = function() {
|
|
27916
|
+
window.FormOnBack = window.FormOnBack || function() {
|
|
27307
27917
|
sendEventCallback2({ type: "FORM_BACK_NAVIGATION" });
|
|
27308
27918
|
};
|
|
27309
|
-
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() {
|
|
27310
27930
|
if (typeof window.commentOnBackFunction === "function") {
|
|
27311
27931
|
window.commentOnBackFunction();
|
|
27312
27932
|
}
|
|
27313
27933
|
};
|
|
27314
|
-
window.submitComments = function() {
|
|
27934
|
+
window.submitComments = window.submitComments || function() {
|
|
27315
27935
|
if (typeof window.submitCommentsFunction === "function") {
|
|
27316
27936
|
window.submitCommentsFunction();
|
|
27317
27937
|
}
|
|
27318
27938
|
};
|
|
27319
|
-
window.FormOnSave = function() {
|
|
27939
|
+
window.FormOnSave = window.FormOnSave || function() {
|
|
27320
27940
|
if (typeof window.formOnSaveFunction === "function") {
|
|
27321
27941
|
window.formOnSaveFunction();
|
|
27322
27942
|
}
|
|
27323
27943
|
};
|
|
27324
|
-
window.FormOnSubmit = function() {
|
|
27944
|
+
window.FormOnSubmit = window.FormOnSubmit || function() {
|
|
27325
27945
|
if (typeof window.formOnSubmitFunction === "function") {
|
|
27326
27946
|
window.formOnSubmitFunction();
|
|
27327
27947
|
}
|
|
@@ -48243,6 +48863,14 @@ async function startCameraScanner() {
|
|
|
48243
48863
|
|
|
48244
48864
|
showBarcodeError(errorMessage);
|
|
48245
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
|
+
}
|
|
48246
48874
|
}
|
|
48247
48875
|
}
|
|
48248
48876
|
|
|
@@ -48626,7 +49254,7 @@ function injectBarcodeModalStyles() {
|
|
|
48626
49254
|
|
|
48627
49255
|
(function(){
|
|
48628
49256
|
// Listen for "getLocation" custom event
|
|
48629
|
-
|
|
49257
|
+
document.addEventListener("getLocation", function (event) {
|
|
48630
49258
|
const { compObj, controlId } = event.detail;
|
|
48631
49259
|
window.compId = controlId;
|
|
48632
49260
|
getLocationFromBrowser(controlId); // Pass controlId to getLocationFromBrowser
|
|
@@ -48636,7 +49264,7 @@ function injectBarcodeModalStyles() {
|
|
|
48636
49264
|
function getLocationFromBrowser(componentID) {
|
|
48637
49265
|
// Check if running in Cordova environment
|
|
48638
49266
|
const isCordova = !!(window.cordova || window.PhoneGap || window.phonegap);
|
|
48639
|
-
|
|
49267
|
+
|
|
48640
49268
|
if (!navigator.geolocation) {
|
|
48641
49269
|
showLocationError("Geolocation is not supported by this device.");
|
|
48642
49270
|
return;
|
|
@@ -48657,7 +49285,7 @@ function getLocationFromBrowser(componentID) {
|
|
|
48657
49285
|
showLocationError("Location permission was denied. Please enable it in browser settings and refresh the page.");
|
|
48658
49286
|
return;
|
|
48659
49287
|
}
|
|
48660
|
-
|
|
49288
|
+
|
|
48661
49289
|
if (permissionStatus.state === "granted" || permissionStatus.state === "prompt") {
|
|
48662
49290
|
requestLocation(componentID);
|
|
48663
49291
|
}
|
|
@@ -48675,7 +49303,7 @@ function getLocationFromBrowser(componentID) {
|
|
|
48675
49303
|
|
|
48676
49304
|
function requestLocation(componentID) {
|
|
48677
49305
|
const isCordova = !!(window.cordova || window.PhoneGap || window.phonegap);
|
|
48678
|
-
|
|
49306
|
+
|
|
48679
49307
|
const options = {
|
|
48680
49308
|
enableHighAccuracy: true,
|
|
48681
49309
|
timeout: isCordova ? 30000 : 10000, // Longer timeout for Cordova
|
|
@@ -48692,7 +49320,7 @@ function requestLocation(componentID) {
|
|
|
48692
49320
|
},
|
|
48693
49321
|
});
|
|
48694
49322
|
document.dispatchEvent(customEvent);
|
|
48695
|
-
|
|
49323
|
+
|
|
48696
49324
|
// Send success event
|
|
48697
49325
|
if (window.sendEventCallback) {
|
|
48698
49326
|
window.sendEventCallback({
|
|
@@ -48710,36 +49338,36 @@ function requestLocation(componentID) {
|
|
|
48710
49338
|
}
|
|
48711
49339
|
|
|
48712
49340
|
function handleLocationError(error) {
|
|
48713
|
-
let errorMessage = "
|
|
48714
|
-
let errorCode = "
|
|
48715
|
-
|
|
49341
|
+
let errorMessage = "Location unknown error";
|
|
49342
|
+
let errorCode = "011";
|
|
49343
|
+
|
|
48716
49344
|
switch (error.code) {
|
|
48717
49345
|
case error.PERMISSION_DENIED:
|
|
48718
|
-
errorMessage = "Location permission denied
|
|
49346
|
+
errorMessage = "Location permission denied";
|
|
48719
49347
|
errorCode = "008";
|
|
48720
49348
|
break;
|
|
48721
49349
|
case error.POSITION_UNAVAILABLE:
|
|
48722
|
-
errorMessage = "Location
|
|
49350
|
+
errorMessage = "Location unavailable";
|
|
48723
49351
|
errorCode = "009";
|
|
48724
49352
|
break;
|
|
48725
49353
|
case error.TIMEOUT:
|
|
48726
|
-
errorMessage = "Location request
|
|
49354
|
+
errorMessage = "Location request timeout";
|
|
48727
49355
|
errorCode = "010";
|
|
48728
49356
|
break;
|
|
48729
49357
|
default:
|
|
48730
|
-
errorMessage = "
|
|
49358
|
+
errorMessage = "Location unknown error";
|
|
48731
49359
|
errorCode = "011";
|
|
48732
49360
|
break;
|
|
48733
49361
|
}
|
|
48734
|
-
|
|
49362
|
+
|
|
48735
49363
|
showLocationError(errorMessage);
|
|
48736
49364
|
console.error("Geolocation error:", error);
|
|
48737
|
-
|
|
49365
|
+
|
|
48738
49366
|
// Send error event
|
|
48739
49367
|
if (window.sendEventCallback) {
|
|
48740
49368
|
window.sendEventCallback({
|
|
48741
49369
|
type: "ERROR",
|
|
48742
|
-
|
|
49370
|
+
errorMessage: \`ErrorCode : \${errorCode}, \${errorMessage}\`,
|
|
48743
49371
|
data: { technicalError: error, reason: errorMessage }
|
|
48744
49372
|
});
|
|
48745
49373
|
}
|
|
@@ -48764,9 +49392,9 @@ function showLocationError(message) {
|
|
|
48764
49392
|
text-align: center;
|
|
48765
49393
|
\`;
|
|
48766
49394
|
errorDiv.textContent = message;
|
|
48767
|
-
|
|
49395
|
+
|
|
48768
49396
|
document.body.appendChild(errorDiv);
|
|
48769
|
-
|
|
49397
|
+
|
|
48770
49398
|
// Remove after 5 seconds
|
|
48771
49399
|
setTimeout(() => {
|
|
48772
49400
|
if (errorDiv.parentNode) {
|
|
@@ -48809,15 +49437,18 @@ let capturedImageData = "";
|
|
|
48809
49437
|
function openCameraModal() {
|
|
48810
49438
|
injectCameraModalStyles();
|
|
48811
49439
|
|
|
49440
|
+
// Ensure clean slate: Remove any existing modal if present
|
|
48812
49441
|
const existingModal = document.getElementById("cameraModal");
|
|
49442
|
+
if (existingModal) {
|
|
49443
|
+
existingModal.remove();
|
|
49444
|
+
}
|
|
48813
49445
|
|
|
48814
49446
|
capturedImageData = "";
|
|
48815
49447
|
|
|
48816
|
-
|
|
48817
|
-
const modalHTML = \`
|
|
49448
|
+
const modalHTML = \`
|
|
48818
49449
|
<div id="cameraModal">
|
|
48819
49450
|
<div id="cameraContainer">
|
|
48820
|
-
<video id="cameraVideo"
|
|
49451
|
+
<video id="cameraVideo" playsinline webkit-playsinline muted style="opacity: 0; pointer-events: none;"></video>
|
|
48821
49452
|
<div id="cameraLoader">
|
|
48822
49453
|
<div class="loader-spinner"></div>
|
|
48823
49454
|
<p class="loader-text">Starting camera...</p>
|
|
@@ -48828,6 +49459,11 @@ function openCameraModal() {
|
|
|
48828
49459
|
<path d="M18 6L6 18M6 6L18 18" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
|
48829
49460
|
</svg>
|
|
48830
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>
|
|
48831
49467
|
<div id="captureButton" style="opacity: 0; pointer-events: none;">
|
|
48832
49468
|
<div class="capture-ring">
|
|
48833
49469
|
<div class="capture-inner"></div>
|
|
@@ -48837,35 +49473,18 @@ function openCameraModal() {
|
|
|
48837
49473
|
</div>
|
|
48838
49474
|
</div>
|
|
48839
49475
|
\`;
|
|
48840
|
-
|
|
48841
|
-
|
|
48842
|
-
|
|
48843
|
-
|
|
48844
|
-
|
|
48845
|
-
|
|
48846
|
-
// Reset UI state when reopening
|
|
48847
|
-
const video = document.getElementById("cameraVideo");
|
|
48848
|
-
const loader = document.getElementById("cameraLoader");
|
|
48849
|
-
const captureBtn = document.getElementById("captureButton");
|
|
48850
|
-
|
|
48851
|
-
if (video) {
|
|
48852
|
-
video.style.opacity = "0";
|
|
48853
|
-
video.srcObject = null;
|
|
48854
|
-
}
|
|
48855
|
-
if (loader) {
|
|
48856
|
-
loader.style.display = "flex";
|
|
48857
|
-
loader.style.opacity = "1";
|
|
48858
|
-
}
|
|
48859
|
-
if (captureBtn) {
|
|
48860
|
-
captureBtn.style.opacity = "0";
|
|
48861
|
-
captureBtn.style.pointerEvents = "none";
|
|
48862
|
-
}
|
|
48863
|
-
}
|
|
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
|
+
});
|
|
48864
49482
|
|
|
49483
|
+
// Small delay to ensure DOM is ready
|
|
48865
49484
|
setTimeout(startCameraStream, 100);
|
|
48866
49485
|
}
|
|
48867
49486
|
|
|
48868
|
-
async function startCameraStream() {
|
|
49487
|
+
async function startCameraStream(deviceId = null) {
|
|
48869
49488
|
if (videoStream) {
|
|
48870
49489
|
try {
|
|
48871
49490
|
videoStream.getTracks().forEach(track => track.stop());
|
|
@@ -48876,42 +49495,84 @@ async function startCameraStream() {
|
|
|
48876
49495
|
}
|
|
48877
49496
|
|
|
48878
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
|
+
|
|
48879
49508
|
const video = document.getElementById("cameraVideo");
|
|
48880
49509
|
if (!video) {
|
|
48881
49510
|
alert("Camera video element not found.");
|
|
48882
49511
|
return;
|
|
48883
49512
|
}
|
|
48884
49513
|
|
|
48885
|
-
//
|
|
48886
|
-
|
|
48887
|
-
|
|
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
|
+
};
|
|
48888
49527
|
|
|
48889
|
-
if (
|
|
48890
|
-
|
|
48891
|
-
|
|
49528
|
+
if (deviceId) {
|
|
49529
|
+
constraints.video.deviceId = { exact: deviceId };
|
|
49530
|
+
} else {
|
|
49531
|
+
constraints.video.facingMode = "environment";
|
|
48892
49532
|
}
|
|
48893
49533
|
|
|
48894
|
-
|
|
48895
|
-
const backCamera = videoDevices.find(device =>
|
|
48896
|
-
device.label.toLowerCase().includes('back') ||
|
|
48897
|
-
device.label.toLowerCase().includes('rear')
|
|
48898
|
-
) || videoDevices[0];
|
|
49534
|
+
const streamPromise = navigator.mediaDevices.getUserMedia(constraints);
|
|
48899
49535
|
|
|
48900
|
-
|
|
48901
|
-
|
|
48902
|
-
|
|
48903
|
-
|
|
48904
|
-
|
|
48905
|
-
|
|
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.");
|
|
48906
49545
|
}
|
|
48907
|
-
|
|
49546
|
+
throw err;
|
|
49547
|
+
}
|
|
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;
|
|
48908
49558
|
|
|
49559
|
+
// Assign stream
|
|
48909
49560
|
video.srcObject = videoStream;
|
|
48910
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
|
+
|
|
48911
49570
|
// Wait for video to start playing, then hide loader
|
|
48912
49571
|
video.onloadedmetadata = () => {
|
|
48913
|
-
|
|
48914
|
-
|
|
49572
|
+
// Once permission is granted and stream starts, listing devices will return labels
|
|
49573
|
+
populateCameraDevices();
|
|
49574
|
+
|
|
49575
|
+
const showUI = () => {
|
|
48915
49576
|
const loader = document.getElementById("cameraLoader");
|
|
48916
49577
|
const captureBtn = document.getElementById("captureButton");
|
|
48917
49578
|
|
|
@@ -48919,23 +49580,34 @@ async function startCameraStream() {
|
|
|
48919
49580
|
loader.style.display = "none";
|
|
48920
49581
|
loader.style.opacity = "0";
|
|
48921
49582
|
}
|
|
49583
|
+
|
|
48922
49584
|
video.style.opacity = "1";
|
|
49585
|
+
|
|
48923
49586
|
if (captureBtn) {
|
|
48924
49587
|
captureBtn.style.opacity = "1";
|
|
48925
49588
|
captureBtn.style.pointerEvents = "all";
|
|
48926
49589
|
}
|
|
49590
|
+
};
|
|
48927
49591
|
|
|
49592
|
+
video.play().then(() => {
|
|
49593
|
+
showUI();
|
|
48928
49594
|
cameraStarted = true;
|
|
48929
49595
|
}).catch(err => {
|
|
48930
49596
|
console.error("Video play error:", err);
|
|
48931
|
-
|
|
48932
|
-
|
|
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
|
+
}
|
|
48933
49605
|
});
|
|
48934
49606
|
};
|
|
48935
49607
|
|
|
48936
49608
|
} catch (err) {
|
|
48937
49609
|
console.error("Camera start error:", err);
|
|
48938
|
-
let errorMessage = "Failed to start camera";
|
|
49610
|
+
let errorMessage = err.message || "Failed to start camera";
|
|
48939
49611
|
|
|
48940
49612
|
if (err.name === 'NotAllowedError' || err.name === 'PermissionDeniedError') {
|
|
48941
49613
|
errorMessage = "Camera permission denied. Please allow camera access and try again.";
|
|
@@ -48951,18 +49623,50 @@ async function startCameraStream() {
|
|
|
48951
49623
|
errorMessage = "Camera access was interrupted.";
|
|
48952
49624
|
}
|
|
48953
49625
|
|
|
48954
|
-
|
|
49626
|
+
alert(errorMessage);
|
|
49627
|
+
closeCameraModal();
|
|
49628
|
+
}
|
|
49629
|
+
}
|
|
48955
49630
|
|
|
48956
|
-
|
|
48957
|
-
|
|
48958
|
-
|
|
48959
|
-
|
|
48960
|
-
|
|
48961
|
-
|
|
49631
|
+
async function populateCameraDevices() {
|
|
49632
|
+
const select = document.getElementById("cameraSelect");
|
|
49633
|
+
if (!select) return;
|
|
49634
|
+
|
|
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);
|
|
48962
49660
|
});
|
|
48963
|
-
}
|
|
48964
49661
|
|
|
48965
|
-
|
|
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);
|
|
48966
49670
|
}
|
|
48967
49671
|
}
|
|
48968
49672
|
|
|
@@ -49032,19 +49736,19 @@ function closeCameraModal() {
|
|
|
49032
49736
|
const modal = document.getElementById("cameraModal");
|
|
49033
49737
|
|
|
49034
49738
|
if (videoStream) {
|
|
49035
|
-
|
|
49739
|
+
try {
|
|
49740
|
+
videoStream.getTracks().forEach(track => track.stop());
|
|
49741
|
+
} catch (e) {
|
|
49742
|
+
console.warn("Error stopping tracks", e);
|
|
49743
|
+
}
|
|
49036
49744
|
videoStream = null;
|
|
49037
49745
|
cameraStarted = false;
|
|
49038
49746
|
}
|
|
49039
49747
|
|
|
49040
|
-
//
|
|
49041
|
-
|
|
49042
|
-
|
|
49043
|
-
video.srcObject = null;
|
|
49044
|
-
video.style.opacity = "0";
|
|
49748
|
+
// Completely remove from DOM to reset video element state for iOS
|
|
49749
|
+
if (modal) {
|
|
49750
|
+
modal.remove();
|
|
49045
49751
|
}
|
|
49046
|
-
|
|
49047
|
-
if (modal) modal.style.display = "none";
|
|
49048
49752
|
}
|
|
49049
49753
|
|
|
49050
49754
|
function injectCameraModalStyles() {
|
|
@@ -49075,6 +49779,7 @@ function injectCameraModalStyles() {
|
|
|
49075
49779
|
object-fit: cover;
|
|
49076
49780
|
background: #000;
|
|
49077
49781
|
transition: opacity 0.3s ease;
|
|
49782
|
+
pointer-events: none;
|
|
49078
49783
|
}
|
|
49079
49784
|
|
|
49080
49785
|
#cameraLoader {
|
|
@@ -49155,6 +49860,39 @@ function injectCameraModalStyles() {
|
|
|
49155
49860
|
background: rgba(0, 0, 0, 0.7);
|
|
49156
49861
|
}
|
|
49157
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
|
+
|
|
49158
49896
|
#captureButton {
|
|
49159
49897
|
position: absolute;
|
|
49160
49898
|
bottom: 40px;
|
|
@@ -49221,6 +49959,11 @@ function injectCameraModalStyles() {
|
|
|
49221
49959
|
bottom: env(safe-area-inset-bottom, 40px);
|
|
49222
49960
|
bottom: max(40px, env(safe-area-inset-bottom));
|
|
49223
49961
|
}
|
|
49962
|
+
|
|
49963
|
+
.camera-select-container {
|
|
49964
|
+
top: env(safe-area-inset-top, 20px);
|
|
49965
|
+
top: max(20px, env(safe-area-inset-top));
|
|
49966
|
+
}
|
|
49224
49967
|
}
|
|
49225
49968
|
|
|
49226
49969
|
/* Landscape mode adjustments */
|
|
@@ -49855,7 +50598,7 @@ see README and LICENSE for details
|
|
|
49855
50598
|
|
|
49856
50599
|
let flag = false;
|
|
49857
50600
|
class SmartStorage {
|
|
49858
|
-
constructor() {}
|
|
50601
|
+
constructor() { }
|
|
49859
50602
|
|
|
49860
50603
|
static get title() {
|
|
49861
50604
|
return "SmartStorage";
|
|
@@ -49881,15 +50624,38 @@ class SmartStorage {
|
|
|
49881
50624
|
|
|
49882
50625
|
return new Promise((resolve, reject) => {
|
|
49883
50626
|
const request = indexedDB.open("Forms-Attachments", 3);
|
|
50627
|
+
|
|
49884
50628
|
request.onsuccess = function (event) {
|
|
49885
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
|
+
}
|
|
49886
50646
|
resolve(db);
|
|
49887
50647
|
};
|
|
49888
50648
|
|
|
49889
50649
|
request.onupgradeneeded = function (e) {
|
|
49890
50650
|
const db = e.target.result;
|
|
49891
|
-
db.
|
|
49892
|
-
|
|
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\`.
|
|
49893
50659
|
};
|
|
49894
50660
|
|
|
49895
50661
|
request.onerror = function (e) {
|
|
@@ -49916,6 +50682,7 @@ class SmartStorage {
|
|
|
49916
50682
|
size: file.size,
|
|
49917
50683
|
type: file.type,
|
|
49918
50684
|
url,
|
|
50685
|
+
mode: "A",
|
|
49919
50686
|
};
|
|
49920
50687
|
if (
|
|
49921
50688
|
window.platform.isBrowser ||
|
|
@@ -49937,6 +50704,7 @@ class SmartStorage {
|
|
|
49937
50704
|
type: file.type,
|
|
49938
50705
|
url: url,
|
|
49939
50706
|
id,
|
|
50707
|
+
mode: "A",
|
|
49940
50708
|
});
|
|
49941
50709
|
};
|
|
49942
50710
|
} else {
|
|
@@ -49947,6 +50715,7 @@ class SmartStorage {
|
|
|
49947
50715
|
type: file.type,
|
|
49948
50716
|
url: url,
|
|
49949
50717
|
id,
|
|
50718
|
+
mode: "A",
|
|
49950
50719
|
});
|
|
49951
50720
|
}
|
|
49952
50721
|
};
|
|
@@ -50033,6 +50802,7 @@ class SmartStorage {
|
|
|
50033
50802
|
size: blobObject.size,
|
|
50034
50803
|
type: file.type,
|
|
50035
50804
|
url: file.url,
|
|
50805
|
+
mode: file.mode || "G",
|
|
50036
50806
|
};
|
|
50037
50807
|
const trans = db.transaction(["Files"], "readwrite");
|
|
50038
50808
|
const addReq = trans.objectStore("Files").put(data, id);
|
|
@@ -50692,7 +51462,21 @@ class SmartFileComponent extends FieldComponent {
|
|
|
50692
51462
|
}
|
|
50693
51463
|
|
|
50694
51464
|
getValue() {
|
|
50695
|
-
|
|
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);
|
|
50696
51480
|
}
|
|
50697
51481
|
|
|
50698
51482
|
get defaultValue() {
|
|
@@ -51015,6 +51799,13 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51015
51799
|
new SmartStorage().markFileAsDeleted(fileInfo.id);
|
|
51016
51800
|
this.deleteFile(fileInfo);
|
|
51017
51801
|
event.preventDefault();
|
|
51802
|
+
|
|
51803
|
+
fileInfo.mode = "D";
|
|
51804
|
+
if (!this.deletedFiles) {
|
|
51805
|
+
this.deletedFiles = [];
|
|
51806
|
+
}
|
|
51807
|
+
this.deletedFiles.push(fileInfo);
|
|
51808
|
+
|
|
51018
51809
|
this.splice(index);
|
|
51019
51810
|
this.redraw();
|
|
51020
51811
|
});
|
|
@@ -51269,10 +52060,8 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51269
52060
|
let id = this.component.id;
|
|
51270
52061
|
isfileBrowse = false;
|
|
51271
52062
|
|
|
51272
|
-
//
|
|
51273
|
-
|
|
51274
|
-
|
|
51275
|
-
if (window.platform.isAndroid) {
|
|
52063
|
+
// Dispatch custom camera event for both Android and iOS
|
|
52064
|
+
if (window.platform.isAndroid || window.platform.iosPlatform) {
|
|
51276
52065
|
window.isListenerSet = false;
|
|
51277
52066
|
let eventCustom = new CustomEvent("openCamera", {
|
|
51278
52067
|
detail: {
|
|
@@ -51656,6 +52445,24 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51656
52445
|
if (this.component.storage && files && files.length) {
|
|
51657
52446
|
// if (this.component.storage && files) {
|
|
51658
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
|
+
}
|
|
51659
52466
|
const fileName = uniqueName(
|
|
51660
52467
|
file.name,
|
|
51661
52468
|
this.component.fileNameTemplate,
|
|
@@ -51698,8 +52505,9 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51698
52505
|
// Check if file with the same name is being uploaded
|
|
51699
52506
|
var fileWithSameNameUploaded = false;
|
|
51700
52507
|
if (window.platform.iosPlatform) {
|
|
52508
|
+
// For iOS, compare using the escaped filename (after timestamp modification)
|
|
51701
52509
|
fileWithSameNameUploaded = this.dataValue.some(
|
|
51702
|
-
(fileStatus) => fileStatus.
|
|
52510
|
+
(fileStatus) => fileStatus.originalName === escapedFileName
|
|
51703
52511
|
);
|
|
51704
52512
|
} else {
|
|
51705
52513
|
fileWithSameNameUploaded = isfileBrowse
|
|
@@ -51909,19 +52717,27 @@ class SmartFileComponent extends FieldComponent {
|
|
|
51909
52717
|
fileInfo.originalName = escapedFileName;
|
|
51910
52718
|
fileInfo.hash = fileUpload.hash;
|
|
51911
52719
|
fileInfo.compnentId = this.component.id;
|
|
52720
|
+
fileInfo.mode = fileUpload.mode || "A";
|
|
51912
52721
|
if (!this.hasValue()) {
|
|
51913
52722
|
this.dataValue = [];
|
|
51914
52723
|
}
|
|
51915
52724
|
if (replace) {
|
|
51916
|
-
let ind;
|
|
52725
|
+
let ind = -1;
|
|
51917
52726
|
for (let i = 0; i < this.dataValue.length; i++) {
|
|
51918
52727
|
if (this.dataValue[i].originalName == fileInfo.originalName) {
|
|
51919
52728
|
console.log("original name matches");
|
|
51920
52729
|
ind = i;
|
|
52730
|
+
break;
|
|
51921
52731
|
}
|
|
51922
52732
|
}
|
|
51923
52733
|
if (ind !== -1) {
|
|
51924
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
|
+
|
|
51925
52741
|
console.log("originalFileId = " + originalFileId);
|
|
51926
52742
|
this.dataValue[ind] = fileInfo;
|
|
51927
52743
|
let eventCustom = new CustomEvent(
|
|
@@ -59468,7 +60284,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59468
60284
|
return {
|
|
59469
60285
|
...super.conditionOperatorsSettings,
|
|
59470
60286
|
valueComponent(classComp) {
|
|
59471
|
-
const valueComp = { ...
|
|
60287
|
+
const valueComp = { ...classComp, type: 'select' };
|
|
59472
60288
|
|
|
59473
60289
|
if (isSelectResourceWithObjectValue(classComp)) {
|
|
59474
60290
|
valueComp.reference = false;
|
|
@@ -59620,7 +60436,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59620
60436
|
return this.component.valueProperty;
|
|
59621
60437
|
}
|
|
59622
60438
|
// Force values datasource to use values without actually setting it on the component settings.
|
|
59623
|
-
|
|
60439
|
+
if (this.component.dataSrc === 'values') {
|
|
59624
60440
|
return 'value';
|
|
59625
60441
|
}
|
|
59626
60442
|
return '';
|
|
@@ -59658,10 +60474,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59658
60474
|
|
|
59659
60475
|
get shouldInitialLoad() {
|
|
59660
60476
|
if (this.component.widget === 'html5' &&
|
|
59661
|
-
|
|
59662
|
-
|
|
59663
|
-
|
|
59664
|
-
|
|
60477
|
+
this.isEntireObjectDisplay() &&
|
|
60478
|
+
this.component.searchField &&
|
|
60479
|
+
this.dataValue) {
|
|
60480
|
+
return false;
|
|
59665
60481
|
}
|
|
59666
60482
|
|
|
59667
60483
|
return super.shouldLoad;
|
|
@@ -59696,7 +60512,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59696
60512
|
if (this.component.multiple && _.isArray(this.dataValue) ? this.dataValue.find((val) => value === val) : (this.dataValue === value)) {
|
|
59697
60513
|
const selectData = this.selectData;
|
|
59698
60514
|
if (selectData) {
|
|
59699
|
-
const templateValue = this.component.reference && value && (value._id
|
|
60515
|
+
const templateValue = this.component.reference && value && (value._id ? value._id.toString() : value);
|
|
59700
60516
|
if (!this.templateData || !this.templateData[templateValue]) {
|
|
59701
60517
|
this.getOptionTemplate(data, value);
|
|
59702
60518
|
}
|
|
@@ -59723,7 +60539,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59723
60539
|
});
|
|
59724
60540
|
}
|
|
59725
60541
|
|
|
59726
|
-
|
|
60542
|
+
if (data.data) {
|
|
59727
60543
|
// checking additional fields in the template for the selected Entire Object option
|
|
59728
60544
|
const hasNestedFields = /item\\.data\\.\\w*/g.test(this.component.template);
|
|
59729
60545
|
data.data = this.isEntireObjectDisplay() && _.isObject(data.data) && !hasNestedFields ?
|
|
@@ -59742,8 +60558,8 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59742
60558
|
hasTranslator = this.i18next.translator;
|
|
59743
60559
|
}
|
|
59744
60560
|
if (!label || (hasTranslator && !this.t(label, {
|
|
59745
|
-
|
|
59746
|
-
|
|
60561
|
+
_userInput: true
|
|
60562
|
+
}))) return;
|
|
59747
60563
|
return hasTranslator ? template.replace(label, this.t(label, {
|
|
59748
60564
|
_userInput: true
|
|
59749
60565
|
})) : label;
|
|
@@ -59770,7 +60586,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59770
60586
|
// ...idPath
|
|
59771
60587
|
// };
|
|
59772
60588
|
|
|
59773
|
-
|
|
60589
|
+
const option = Object.assign({
|
|
59774
60590
|
value: this.getOptionValue(value),
|
|
59775
60591
|
label,
|
|
59776
60592
|
}, idPath);
|
|
@@ -59926,7 +60742,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59926
60742
|
if (this.root && this.root.options.editForm && this.root.options.editForm._id && this.root.options.editForm._id === item._id) return;
|
|
59927
60743
|
const itemValueAndLabel = this.selectValueAndLabel(item);
|
|
59928
60744
|
this.addOption(itemValueAndLabel.value, itemValueAndLabel.label, {}, _.get(item, this.component.idPath, String(index)));
|
|
59929
|
-
|
|
60745
|
+
|
|
59930
60746
|
});
|
|
59931
60747
|
if (this.choices) {
|
|
59932
60748
|
if ((this.component.dataSrc === 'masterdata') && this.component.masterdata) {
|
|
@@ -59968,10 +60784,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59968
60784
|
// If a value is provided, then select it.
|
|
59969
60785
|
if (!this.isEmpty()) {
|
|
59970
60786
|
if (localStorage.getItem('renderMode') === 'html') {
|
|
59971
|
-
|
|
59972
|
-
|
|
59973
|
-
|
|
59974
|
-
|
|
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();
|
|
59975
60791
|
|
|
59976
60792
|
if (items.length > 0) {
|
|
59977
60793
|
if (this.component.multiple) {
|
|
@@ -59984,13 +60800,13 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
59984
60800
|
});
|
|
59985
60801
|
} else {
|
|
59986
60802
|
}
|
|
60803
|
+
}
|
|
60804
|
+
} else {
|
|
60805
|
+
this.setValue(this.dataValue, {
|
|
60806
|
+
noUpdateEvent: true
|
|
60807
|
+
});
|
|
59987
60808
|
}
|
|
59988
|
-
}else{
|
|
59989
|
-
this.setValue(this.dataValue, {
|
|
59990
|
-
noUpdateEvent: true
|
|
59991
|
-
});
|
|
59992
|
-
}
|
|
59993
|
-
}else if (this.shouldAddDefaultValue && !this.options.readOnly) {
|
|
60809
|
+
} else if (this.shouldAddDefaultValue && !this.options.readOnly) {
|
|
59994
60810
|
// If a default value is provided then select it.
|
|
59995
60811
|
const defaultValue = this.defaultValue;
|
|
59996
60812
|
if (!this.isEmpty(defaultValue)) {
|
|
@@ -60297,32 +61113,32 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60297
61113
|
} else {
|
|
60298
61114
|
if (!this.component.dropdownOpened && this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60299
61115
|
let result = [];
|
|
60300
|
-
if(this.component.multiple && this.component.masterdata){
|
|
60301
|
-
this.data[this.key].forEach(item =>
|
|
61116
|
+
if (this.component.multiple && this.component.masterdata) {
|
|
61117
|
+
this.data[this.key].forEach(item =>
|
|
60302
61118
|
this.component.masterdata.filter((value) => {
|
|
60303
61119
|
const propValue = value[this.component.valueProperty];
|
|
60304
|
-
|
|
60305
|
-
|
|
60306
|
-
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)) {
|
|
60307
61123
|
result.push(value)
|
|
60308
61124
|
}
|
|
60309
61125
|
})
|
|
60310
61126
|
);
|
|
60311
61127
|
// result = this.component.masterdata;
|
|
60312
|
-
}else{
|
|
60313
|
-
if(this.component.masterdata){
|
|
60314
|
-
|
|
60315
|
-
|
|
60316
|
-
|
|
60317
|
-
|
|
60318
|
-
|
|
60319
|
-
|
|
60320
|
-
|
|
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
|
+
}
|
|
60321
61137
|
}
|
|
60322
61138
|
const unique = result.filter((obj, index) => {
|
|
60323
61139
|
return index === result.findIndex(o => obj[this.component.valueProperty] === o[this.component.valueProperty]);
|
|
60324
|
-
|
|
60325
|
-
|
|
61140
|
+
});
|
|
61141
|
+
this.setItems(unique);
|
|
60326
61142
|
}
|
|
60327
61143
|
}
|
|
60328
61144
|
}
|
|
@@ -60483,9 +61299,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60483
61299
|
get active() {
|
|
60484
61300
|
if ((this.component.dataSrc === 'masterdata') && this.component.masterdata) {
|
|
60485
61301
|
return !this.component.lazyLoad || this.activated;
|
|
60486
|
-
}else{
|
|
60487
|
-
|
|
60488
|
-
|
|
61302
|
+
} else {
|
|
61303
|
+
// return !this.component.lazyLoad || this.activated || this.options.readOnly;
|
|
61304
|
+
return !this.component.lazyLoad || this.activated;
|
|
60489
61305
|
}
|
|
60490
61306
|
}
|
|
60491
61307
|
|
|
@@ -60559,8 +61375,8 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60559
61375
|
searchChoices: !this.component.searchField,
|
|
60560
61376
|
searchFields: _.get(this, 'component.searchFields', ['label']),
|
|
60561
61377
|
shadowRoot: this.root ? this.root.shadowRoot : null,
|
|
60562
|
-
|
|
60563
|
-
_.get(this, 'component.fuseOptions', {}),
|
|
61378
|
+
fuseOptions: this.component.useExactSearch ? Object.assign(fuseObj, commonFuseOptions) : Object.assign({},
|
|
61379
|
+
_.get(this, 'component.fuseOptions', {}),
|
|
60564
61380
|
Object.assign(fuseObj1, commonFuseOptions)
|
|
60565
61381
|
),
|
|
60566
61382
|
valueComparer: _.isEqual,
|
|
@@ -60728,17 +61544,17 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60728
61544
|
}
|
|
60729
61545
|
this.isFromSearch = false;
|
|
60730
61546
|
});
|
|
60731
|
-
|
|
60732
|
-
|
|
60733
|
-
|
|
60734
|
-
|
|
60735
|
-
|
|
60736
|
-
|
|
60737
|
-
|
|
60738
|
-
|
|
60739
|
-
|
|
60740
|
-
|
|
60741
|
-
|
|
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));
|
|
60742
61558
|
|
|
60743
61559
|
this.addEventListener(input, 'stopSearch', () => this.triggerUpdate());
|
|
60744
61560
|
this.addEventListener(input, 'hideDropdown', () => {
|
|
@@ -60753,9 +61569,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60753
61569
|
if (this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60754
61570
|
selData = this.component.masterdata.filter((value) => {
|
|
60755
61571
|
const propValue = value[this.component.valueProperty];
|
|
60756
|
-
|
|
60757
|
-
|
|
60758
|
-
|
|
61572
|
+
// Convert to string only if necessary
|
|
61573
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61574
|
+
return valPropData?.includes(this.data[this.key]);
|
|
60759
61575
|
|
|
60760
61576
|
})
|
|
60761
61577
|
}
|
|
@@ -60848,10 +61664,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60848
61664
|
setDropdownPosition() {
|
|
60849
61665
|
let dropdown;
|
|
60850
61666
|
let container;
|
|
60851
|
-
if(this.choices && this.choices.dropdown && this.choices.dropdown.element){
|
|
60852
|
-
|
|
61667
|
+
if (this.choices && this.choices.dropdown && this.choices.dropdown.element) {
|
|
61668
|
+
dropdown = this.choices.dropdown.element;
|
|
60853
61669
|
}
|
|
60854
|
-
if(this.choices && this.choices.containerOuter && this.choices.containerOuter.element){
|
|
61670
|
+
if (this.choices && this.choices.containerOuter && this.choices.containerOuter.element) {
|
|
60855
61671
|
container = this.choices.containerOuter.element;
|
|
60856
61672
|
}
|
|
60857
61673
|
|
|
@@ -60936,9 +61752,9 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
60936
61752
|
if (this.data[this.key] && String(this.data[this.key]).length > 0) {
|
|
60937
61753
|
selData = this.component.masterdata.filter((value) => {
|
|
60938
61754
|
const propValue = value[this.component.valueProperty];
|
|
60939
|
-
|
|
60940
|
-
|
|
60941
|
-
|
|
61755
|
+
// Convert to string only if necessary
|
|
61756
|
+
const valPropData = typeof propValue !== 'string' ? String(propValue) : propValue;
|
|
61757
|
+
return valPropData?.includes(this.data[this.key]);
|
|
60942
61758
|
})
|
|
60943
61759
|
}
|
|
60944
61760
|
|
|
@@ -61289,29 +62105,29 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61289
62105
|
|
|
61290
62106
|
setValue(value, flags = {}) {
|
|
61291
62107
|
// console.log("value line 1875" + this.component.label, value)
|
|
61292
|
-
if(value && String(value).length > 0){
|
|
62108
|
+
if (value && String(value).length > 0) {
|
|
61293
62109
|
$(".barcode-select-error").remove();
|
|
61294
62110
|
}
|
|
61295
|
-
|
|
61296
|
-
|
|
61297
|
-
|
|
61298
|
-
|
|
61299
|
-
|
|
61300
|
-
|
|
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
|
+
})
|
|
61301
62129
|
}
|
|
61302
|
-
if (localStorage.getItem('renderMode') === 'html' && this.component.dataSrc === 'masterdata' && !this.component.multiple) {
|
|
61303
|
-
var tmplt = this.component.template;
|
|
61304
|
-
var str1 = tmplt.substring(tmplt.lastIndexOf('.') + 1, tmplt.length);
|
|
61305
|
-
var label = str1.substring(0, str1.indexOf('}'), str1.length);
|
|
61306
|
-
label = label.trim();
|
|
61307
62130
|
|
|
61308
|
-
this.component.masterdata.filter((data) => {
|
|
61309
|
-
if ((value && data[this.component.valueProperty] === value) || (value && data[this.component.valueProperty] === String(value))) {
|
|
61310
|
-
value = data[label];
|
|
61311
|
-
}
|
|
61312
|
-
})
|
|
61313
|
-
}
|
|
61314
|
-
|
|
61315
62131
|
const previousValue = this.dataValue;
|
|
61316
62132
|
// console.log("value line 1900 " + this.component.label, value)
|
|
61317
62133
|
const changed = this.updateValue(value, flags);
|
|
@@ -61323,10 +62139,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61323
62139
|
if (this.component.multiple && Array.isArray(value)) {
|
|
61324
62140
|
value = value.map(value => {
|
|
61325
62141
|
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
61326
|
-
|
|
62142
|
+
console.log("value line 1910 " + this.component.label, value)
|
|
61327
62143
|
return value.toString();
|
|
61328
62144
|
}
|
|
61329
|
-
|
|
62145
|
+
console.log("value line 1914 " + this.component.label, value)
|
|
61330
62146
|
return value;
|
|
61331
62147
|
});
|
|
61332
62148
|
} else {
|
|
@@ -61358,10 +62174,10 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61358
62174
|
// Add the value options.
|
|
61359
62175
|
this.itemsLoaded.then(() => {
|
|
61360
62176
|
this.addValueOptions();
|
|
61361
|
-
|
|
62177
|
+
// console.log("value line 1945 " + this.component.label, value)
|
|
61362
62178
|
this.setChoicesValue(value, hasPreviousValue, flags);
|
|
61363
62179
|
});
|
|
61364
|
-
|
|
62180
|
+
|
|
61365
62181
|
return changed;
|
|
61366
62182
|
}
|
|
61367
62183
|
|
|
@@ -61408,7 +62224,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61408
62224
|
if (hasValue) {
|
|
61409
62225
|
const values = Array.isArray(value) ? value : [value];
|
|
61410
62226
|
if (!_.isEqual(this.dataValue, this.defaultValue) && this.selectOptions.length < 2
|
|
61411
|
-
|
|
62227
|
+
|| (this.selectData && flags.fromSubmission)) {
|
|
61412
62228
|
const { value, label } = this.selectValueAndLabel(this.dataValue);
|
|
61413
62229
|
this.addOption(value, label);
|
|
61414
62230
|
}
|
|
@@ -61481,14 +62297,14 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61481
62297
|
*/
|
|
61482
62298
|
getOptionValue(value) {
|
|
61483
62299
|
return _.isObject(value) && this.isEntireObjectDisplay()
|
|
61484
|
-
|
|
61485
|
-
|
|
61486
|
-
|
|
61487
|
-
|
|
61488
|
-
|
|
61489
|
-
|
|
61490
|
-
|
|
61491
|
-
|
|
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));
|
|
61492
62308
|
}
|
|
61493
62309
|
|
|
61494
62310
|
/**
|
|
@@ -61604,19 +62420,19 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61604
62420
|
items: convertToString(this.getNormalizedValues(), 'value'),
|
|
61605
62421
|
valueProperty: 'value',
|
|
61606
62422
|
} : {
|
|
61607
|
-
|
|
61608
|
-
|
|
61609
|
-
|
|
62423
|
+
items: convertToString(this.getCustomItems(), this.valueProperty),
|
|
62424
|
+
valueProperty: this.valueProperty,
|
|
62425
|
+
};
|
|
61610
62426
|
const getFromValues = () => {
|
|
61611
62427
|
const initialValue = _.find(items, [valueProperty, value]);
|
|
61612
62428
|
const values = this.defaultSchema.data.values || [];
|
|
61613
62429
|
return _.isEqual(initialValue, values[0]) ? '-' : initialValue;
|
|
61614
62430
|
};
|
|
61615
62431
|
value = (this.component.multiple && Array.isArray(value))
|
|
61616
|
-
|
|
61617
|
-
|
|
61618
|
-
|
|
61619
|
-
|
|
62432
|
+
? _.filter(items, (item) => value.includes(item.value))
|
|
62433
|
+
: valueProperty
|
|
62434
|
+
? getFromValues() ?? { value, label: value }
|
|
62435
|
+
: value;
|
|
61620
62436
|
}
|
|
61621
62437
|
|
|
61622
62438
|
if (_.isString(value)) {
|
|
@@ -61632,7 +62448,7 @@ class SmartSelectComponent extends SmartSelectField {
|
|
|
61632
62448
|
if (Array.isArray(value)) {
|
|
61633
62449
|
const items = [];
|
|
61634
62450
|
value.forEach(item => items.push(getTemplateValue(item)));
|
|
61635
|
-
if (this.component.dataSrc === 'resource' &&
|
|
62451
|
+
if (this.component.dataSrc === 'resource' && items.length > 0) {
|
|
61636
62452
|
return items.join(', ');
|
|
61637
62453
|
}
|
|
61638
62454
|
else if (items.length > 0) {
|
|
@@ -65007,12 +65823,22 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
65007
65823
|
submitBtn.style.display = "none";
|
|
65008
65824
|
}
|
|
65009
65825
|
|
|
65010
|
-
// PUBLIC FORM
|
|
65011
|
-
else if (
|
|
65012
|
-
|
|
65013
|
-
|
|
65014
|
-
|
|
65015
|
-
|
|
65826
|
+
// PUBLIC FORM - writemultiple
|
|
65827
|
+
else if (isPublic && permissionMode === "writemultiple") {
|
|
65828
|
+
console.log("Mode: PUBLIC WRITEMULTIPLE \u2192 Show Complete button only (disabled)");
|
|
65829
|
+
saveBtn.style.display = "none";
|
|
65830
|
+
submitBtn.style.display = "";
|
|
65831
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65832
|
+
submitBtn.disabled = true;
|
|
65833
|
+
|
|
65834
|
+
// No dropdown options for public writemultiple
|
|
65835
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65836
|
+
toggleDropdown(saveOption, saveDivider, false);
|
|
65837
|
+
}
|
|
65838
|
+
|
|
65839
|
+
// PUBLIC FORM - writesingle
|
|
65840
|
+
else if (isPublic && permissionMode === "writesingle") {
|
|
65841
|
+
console.log("Mode: PUBLIC WRITESINGLE \u2192 Show submit (disabled)");
|
|
65016
65842
|
saveBtn.style.display = "none";
|
|
65017
65843
|
submitBtn.style.display = "";
|
|
65018
65844
|
submitBtn.innerHTML = '<i class="icon save"></i> Submit';
|
|
@@ -65021,15 +65847,34 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
65021
65847
|
|
|
65022
65848
|
// PRIVATE FORM - writemultiple
|
|
65023
65849
|
else if (isPrivate && permissionMode === "writemultiple") {
|
|
65024
|
-
|
|
65025
|
-
|
|
65026
|
-
|
|
65027
|
-
|
|
65028
|
-
|
|
65029
|
-
|
|
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;
|
|
65030
65874
|
|
|
65031
|
-
|
|
65032
|
-
|
|
65875
|
+
// Initially hide Complete in Dropdown (will show when any field is filled)
|
|
65876
|
+
toggleDropdown(completeOption, completeDivider, false);
|
|
65877
|
+
}
|
|
65033
65878
|
}
|
|
65034
65879
|
|
|
65035
65880
|
// PRIVATE FORM - writesingle
|
|
@@ -65039,7 +65884,7 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
65039
65884
|
);
|
|
65040
65885
|
saveBtn.style.display = "none";
|
|
65041
65886
|
submitBtn.style.display = "";
|
|
65042
|
-
submitBtn.innerHTML = '<i class="icon
|
|
65887
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65043
65888
|
submitBtn.disabled = true;
|
|
65044
65889
|
|
|
65045
65890
|
// Show Save in Dropdown
|
|
@@ -65051,9 +65896,14 @@ function initialButtonSetup(privateExternal, permission) {
|
|
|
65051
65896
|
console.log("Mode: DEFAULT / UNKNOWN \u2192 Show submit (disabled)");
|
|
65052
65897
|
saveBtn.style.display = "none";
|
|
65053
65898
|
submitBtn.style.display = "";
|
|
65054
|
-
submitBtn.innerHTML = '<i class="icon
|
|
65899
|
+
submitBtn.innerHTML = '<i class="icon clipboard large"></i> Submit';
|
|
65055
65900
|
submitBtn.disabled = true;
|
|
65056
65901
|
}
|
|
65902
|
+
|
|
65903
|
+
// Check if More button should be visible based on dropdown content
|
|
65904
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
65905
|
+
window.checkMoreButtonVisibility();
|
|
65906
|
+
}
|
|
65057
65907
|
}
|
|
65058
65908
|
|
|
65059
65909
|
function onChangeButtonSetup(
|
|
@@ -65081,6 +65931,10 @@ function onChangeButtonSetup(
|
|
|
65081
65931
|
);
|
|
65082
65932
|
const isComplete = completionPercentage >= 100;
|
|
65083
65933
|
|
|
65934
|
+
const requireComplete =
|
|
65935
|
+
window.__unviredFormsOptions?.requireCompleteForm === true ||
|
|
65936
|
+
window.__unviredFormsOptions?.requireCompleteForm === "true";
|
|
65937
|
+
|
|
65084
65938
|
// READ ONLY
|
|
65085
65939
|
if (permissionMode === "read") {
|
|
65086
65940
|
console.log("Mode: READ \u2192 Hide all buttons");
|
|
@@ -65096,32 +65950,117 @@ function onChangeButtonSetup(
|
|
|
65096
65950
|
saveBtn.style.display = "none";
|
|
65097
65951
|
submitBtn.style.display = "";
|
|
65098
65952
|
|
|
65099
|
-
// Logic: Disable Complete until 100%
|
|
65100
|
-
submitBtn.disabled = !isComplete;
|
|
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
|
+
}
|
|
65101
65960
|
return;
|
|
65102
65961
|
}
|
|
65103
65962
|
|
|
65104
65963
|
// PRIVATE FORM - writemultiple
|
|
65105
65964
|
if (isPrivate && permissionMode === "writemultiple") {
|
|
65106
65965
|
console.log("Mode: PRIVATE WRITEMULTIPLE");
|
|
65107
|
-
// Main: Save
|
|
65108
|
-
saveBtn.style.display = "";
|
|
65109
|
-
submitBtn.style.display = "none";
|
|
65110
65966
|
|
|
65111
|
-
|
|
65112
|
-
|
|
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) {
|
|
65983
|
+
saveBtn.style.display = "";
|
|
65984
|
+
submitBtn.style.display = "";
|
|
65985
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65986
|
+
|
|
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();
|
|
66034
|
+
}
|
|
65113
66035
|
return;
|
|
65114
66036
|
}
|
|
65115
66037
|
|
|
65116
|
-
// PUBLIC FORM
|
|
65117
|
-
if (
|
|
65118
|
-
|
|
65119
|
-
(permissionMode === "writesingle" || permissionMode === "writemultiple")
|
|
65120
|
-
) {
|
|
65121
|
-
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");
|
|
65122
66041
|
saveBtn.style.display = "none";
|
|
65123
66042
|
submitBtn.style.display = "";
|
|
66043
|
+
submitBtn.innerHTML = '<i class="icon clipboard check large"></i> Complete';
|
|
65124
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
|
+
}
|
|
65125
66064
|
return;
|
|
65126
66065
|
}
|
|
65127
66066
|
|
|
@@ -65130,6 +66069,11 @@ function onChangeButtonSetup(
|
|
|
65130
66069
|
saveBtn.style.display = "none";
|
|
65131
66070
|
submitBtn.style.display = "";
|
|
65132
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
|
+
}
|
|
65133
66077
|
}
|
|
65134
66078
|
|
|
65135
66079
|
// Main form loader
|
|
@@ -65154,7 +66098,22 @@ async function loadRNform(
|
|
|
65154
66098
|
|
|
65155
66099
|
// document.getElementById("formio-cmt").innerHTML = "";
|
|
65156
66100
|
|
|
65157
|
-
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
|
+
}
|
|
65158
66117
|
|
|
65159
66118
|
try {
|
|
65160
66119
|
// Determine form configuration based on mode
|
|
@@ -65193,12 +66152,29 @@ async function loadRNform(
|
|
|
65193
66152
|
formConfig.viewHtml = false;
|
|
65194
66153
|
}
|
|
65195
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)
|
|
65196
66170
|
formObj = await Formio.createForm(
|
|
65197
|
-
|
|
66171
|
+
formElement,
|
|
65198
66172
|
template,
|
|
65199
66173
|
formConfig
|
|
65200
66174
|
);
|
|
65201
66175
|
|
|
66176
|
+
|
|
66177
|
+
|
|
65202
66178
|
// Store initial form data after first change event (ensures all defaults applied)
|
|
65203
66179
|
let initialDataSet = false;
|
|
65204
66180
|
formObj.on("change", () => {
|
|
@@ -65306,6 +66282,9 @@ async function loadRNform(
|
|
|
65306
66282
|
};
|
|
65307
66283
|
}
|
|
65308
66284
|
|
|
66285
|
+
// Calculate initial progress immediately
|
|
66286
|
+
executeProgressCalculation(privateExternal, permission);
|
|
66287
|
+
|
|
65309
66288
|
// Hide FormIO submit button component and wizard buttons in readOnly mode
|
|
65310
66289
|
if (mode == "readOnly") {
|
|
65311
66290
|
const submitComponents = document.querySelectorAll(
|
|
@@ -65357,12 +66336,19 @@ async function loadRNform(
|
|
|
65357
66336
|
if (fileInput) fileInput.setAttribute("accept", "*/*");
|
|
65358
66337
|
});
|
|
65359
66338
|
} catch (error) {
|
|
65360
|
-
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
|
+
|
|
65361
66347
|
sendEventCallback({
|
|
65362
66348
|
type: "ERROR",
|
|
65363
66349
|
errorMessage:
|
|
65364
|
-
"ErrorCode : 005,
|
|
65365
|
-
data: { technicalError: error },
|
|
66350
|
+
"ErrorCode : 005, Formio not rendered the forms",
|
|
66351
|
+
data: { reason: "Failed to render form after retries", technicalError: error },
|
|
65366
66352
|
});
|
|
65367
66353
|
}
|
|
65368
66354
|
}
|
|
@@ -65372,209 +66358,292 @@ let changeTimeout = null;
|
|
|
65372
66358
|
let lastDataHash = null;
|
|
65373
66359
|
let mandatoryFieldsCache = null;
|
|
65374
66360
|
|
|
65375
|
-
|
|
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) {
|
|
65376
66456
|
if (!formObj) return;
|
|
65377
66457
|
|
|
65378
|
-
|
|
65379
|
-
|
|
65380
|
-
if (mandatoryFieldsCache) return mandatoryFieldsCache;
|
|
65381
|
-
|
|
65382
|
-
const cache = [];
|
|
65383
|
-
|
|
65384
|
-
function cacheMandatoryFields(components, path = "") {
|
|
65385
|
-
components.forEach((comp) => {
|
|
65386
|
-
if (!comp) return;
|
|
65387
|
-
const actualComp = comp.component || comp;
|
|
65388
|
-
const fieldPath = path ? \`\${path}.\${actualComp.key}\` : actualComp.key;
|
|
65389
|
-
|
|
65390
|
-
const inputTypes = [
|
|
65391
|
-
"textfield",
|
|
65392
|
-
"textarea",
|
|
65393
|
-
"number",
|
|
65394
|
-
"checkbox",
|
|
65395
|
-
"radio",
|
|
65396
|
-
"select",
|
|
65397
|
-
"selectboxes",
|
|
65398
|
-
"email",
|
|
65399
|
-
"url",
|
|
65400
|
-
"day",
|
|
65401
|
-
"datetime",
|
|
65402
|
-
"file",
|
|
65403
|
-
"datamap",
|
|
65404
|
-
"tree",
|
|
65405
|
-
"survey",
|
|
65406
|
-
"signature",
|
|
65407
|
-
];
|
|
66458
|
+
const data = formObj.data || {};
|
|
66459
|
+
const dataHash = JSON.stringify(data);
|
|
65408
66460
|
|
|
65409
|
-
|
|
65410
|
-
|
|
65411
|
-
actualComp.validate?.required
|
|
65412
|
-
) {
|
|
65413
|
-
cache.push({
|
|
65414
|
-
key: actualComp.key,
|
|
65415
|
-
type: actualComp.type,
|
|
65416
|
-
path: fieldPath,
|
|
65417
|
-
comp: actualComp,
|
|
65418
|
-
});
|
|
65419
|
-
}
|
|
66461
|
+
if (dataHash === lastDataHash) return;
|
|
66462
|
+
lastDataHash = dataHash;
|
|
65420
66463
|
|
|
65421
|
-
|
|
65422
|
-
|
|
65423
|
-
|
|
65424
|
-
|
|
65425
|
-
|
|
65426
|
-
|
|
65427
|
-
|
|
65428
|
-
|
|
65429
|
-
|
|
65430
|
-
|
|
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;
|
|
65431
66495
|
}
|
|
65432
|
-
|
|
65433
|
-
|
|
65434
|
-
|
|
65435
|
-
|
|
65436
|
-
|
|
65437
|
-
|
|
65438
|
-
|
|
65439
|
-
|
|
65440
|
-
|
|
65441
|
-
|
|
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;
|
|
65442
66526
|
}
|
|
65443
|
-
}
|
|
66527
|
+
}
|
|
65444
66528
|
}
|
|
65445
66529
|
|
|
65446
|
-
|
|
65447
|
-
|
|
65448
|
-
|
|
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}%\`;
|
|
65449
66589
|
}
|
|
66590
|
+
}
|
|
65450
66591
|
|
|
65451
|
-
|
|
65452
|
-
|
|
65453
|
-
|
|
65454
|
-
|
|
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]);
|
|
65455
66602
|
}
|
|
66603
|
+
return data[path];
|
|
66604
|
+
}
|
|
65456
66605
|
|
|
65457
|
-
|
|
65458
|
-
|
|
65459
|
-
const data = submission?.data || formObj.data || {};
|
|
65460
|
-
const dataHash = JSON.stringify(data);
|
|
65461
|
-
|
|
65462
|
-
// Skip if data hasn't actually changed
|
|
65463
|
-
if (dataHash === lastDataHash) return;
|
|
65464
|
-
lastDataHash = dataHash;
|
|
65465
|
-
|
|
65466
|
-
const mandatoryFields = buildMandatoryFieldsCache();
|
|
65467
|
-
let mandatory = mandatoryFields.length;
|
|
65468
|
-
let filledMandatory = 0;
|
|
65469
|
-
|
|
65470
|
-
function isFilled(comp, value) {
|
|
65471
|
-
switch (comp.type) {
|
|
65472
|
-
case "selectboxes":
|
|
65473
|
-
return Object.values(value || {}).some(Boolean);
|
|
65474
|
-
case "datamap":
|
|
65475
|
-
case "tree":
|
|
65476
|
-
case "survey":
|
|
65477
|
-
return value && Object.keys(value).length > 0;
|
|
65478
|
-
case "file":
|
|
65479
|
-
return Array.isArray(value) && value.length > 0;
|
|
65480
|
-
case "checkbox":
|
|
65481
|
-
return value === true;
|
|
65482
|
-
case "editgrid":
|
|
65483
|
-
case "datagrid":
|
|
65484
|
-
return Array.isArray(value) && value.length > 0;
|
|
65485
|
-
case "signature":
|
|
65486
|
-
return !!value;
|
|
65487
|
-
default:
|
|
65488
|
-
return value !== undefined && value !== null && value !== "";
|
|
65489
|
-
}
|
|
65490
|
-
}
|
|
66606
|
+
const keys = path.split(".");
|
|
66607
|
+
let current = data;
|
|
65491
66608
|
|
|
65492
|
-
|
|
65493
|
-
|
|
65494
|
-
|
|
65495
|
-
try {
|
|
65496
|
-
const formComp = formObj.getComponent(key);
|
|
65497
|
-
value =
|
|
65498
|
-
formComp && typeof formComp.getValue === "function"
|
|
65499
|
-
? formComp.getValue()
|
|
65500
|
-
: data[key];
|
|
65501
|
-
} catch (e) {
|
|
65502
|
-
value = data[key];
|
|
65503
|
-
}
|
|
66609
|
+
for (let i = 0; i < keys.length; i++) {
|
|
66610
|
+
const key = keys[i];
|
|
66611
|
+
if (current === undefined || current === null) return undefined;
|
|
65504
66612
|
|
|
65505
|
-
|
|
65506
|
-
|
|
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
|
+
}
|
|
65507
66619
|
|
|
65508
|
-
|
|
65509
|
-
|
|
65510
|
-
|
|
65511
|
-
|
|
65512
|
-
filled
|
|
65513
|
-
);
|
|
65514
|
-
});
|
|
66620
|
+
current = current[key];
|
|
66621
|
+
}
|
|
66622
|
+
return current;
|
|
66623
|
+
}
|
|
65515
66624
|
|
|
65516
|
-
|
|
65517
|
-
|
|
65518
|
-
const completion =
|
|
65519
|
-
mandatory === 0 ? 100 : Math.round((filledMandatory / mandatory) * 100);
|
|
65520
|
-
console.log("\u{1F4CA} Completion %:", completion);
|
|
65521
|
-
|
|
65522
|
-
onChangeButtonSetup(
|
|
65523
|
-
completion,
|
|
65524
|
-
formObj.data,
|
|
65525
|
-
privateExternal,
|
|
65526
|
-
permission
|
|
65527
|
-
);
|
|
66625
|
+
function setupOnChange(privateExternal, permission) {
|
|
66626
|
+
if (!formObj) return;
|
|
65528
66627
|
|
|
65529
|
-
|
|
65530
|
-
|
|
65531
|
-
|
|
65532
|
-
|
|
65533
|
-
|
|
65534
|
-
|
|
65535
|
-
// Set bar width
|
|
65536
|
-
bar.style.width = \`\${completion}%\`;
|
|
65537
|
-
|
|
65538
|
-
// Update badge text
|
|
65539
|
-
badge.textContent = \`\${completion}%\`;
|
|
65540
|
-
|
|
65541
|
-
// Calculate badge left relative to container
|
|
65542
|
-
let left = completion;
|
|
65543
|
-
|
|
65544
|
-
// Edge cases: keep badge inside screen
|
|
65545
|
-
if (completion <= 0) {
|
|
65546
|
-
left = 0.5; // slightly inside
|
|
65547
|
-
bar.style.width = \`\${0.5}%\`;
|
|
65548
|
-
if (window.innerWidth > 768) {
|
|
65549
|
-
badge.style.transform = "translateX(2%)"; // desktop
|
|
65550
|
-
} else if (window.innerWidth > 480) {
|
|
65551
|
-
badge.style.transform = "translateX(2%)"; // tablet
|
|
65552
|
-
} else if (window.innerWidth > 360) {
|
|
65553
|
-
badge.style.transform = "translateX(2%)"; // mobile
|
|
65554
|
-
} else {
|
|
65555
|
-
badge.style.transform = "translateX(1%)"; // very small phone
|
|
65556
|
-
}
|
|
65557
|
-
}
|
|
65558
|
-
if (completion >= 100) {
|
|
65559
|
-
left = 99.5; // slightly inside
|
|
65560
|
-
// Responsive translateX for different screen widths
|
|
65561
|
-
if (window.innerWidth > 768) {
|
|
65562
|
-
badge.style.transform = "translateX(-65%)"; // desktop
|
|
65563
|
-
} else if (window.innerWidth > 480) {
|
|
65564
|
-
badge.style.transform = "translateX(-85%)"; // tablet
|
|
65565
|
-
} else if (window.innerWidth > 360) {
|
|
65566
|
-
badge.style.transform = "translateX(-95%)"; // mobile
|
|
65567
|
-
} else {
|
|
65568
|
-
badge.style.transform = "translateX(-105%)"; // very small phone
|
|
65569
|
-
}
|
|
65570
|
-
}
|
|
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
|
+
}
|
|
65571
66633
|
|
|
65572
|
-
|
|
65573
|
-
|
|
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);
|
|
65574
66645
|
}, 300); // 300ms debounce delay
|
|
65575
66646
|
});
|
|
65576
|
-
|
|
65577
|
-
// removed ad-hoc setTimeout: rely on formObj.formReady and LessRenderingComplete events
|
|
65578
66647
|
}
|
|
65579
66648
|
|
|
65580
66649
|
// Function to convert file objects back to IDs
|
|
@@ -65635,6 +66704,27 @@ function FormOnSubmit() {
|
|
|
65635
66704
|
attachmentfileKeysSDK
|
|
65636
66705
|
);
|
|
65637
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
|
+
|
|
65638
66728
|
formObj
|
|
65639
66729
|
.submit()
|
|
65640
66730
|
.then((result) => {
|
|
@@ -65652,7 +66742,19 @@ function FormOnSubmit() {
|
|
|
65652
66742
|
})
|
|
65653
66743
|
.catch((error) => {
|
|
65654
66744
|
console.error(error);
|
|
65655
|
-
|
|
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
|
+
});
|
|
65656
66758
|
});
|
|
65657
66759
|
}
|
|
65658
66760
|
|
|
@@ -65684,9 +66786,7 @@ async function loadComments() {
|
|
|
65684
66786
|
window.FORM_VOB_ARR,
|
|
65685
66787
|
window.FORM_USERS_LIST || []
|
|
65686
66788
|
);
|
|
65687
|
-
|
|
65688
|
-
showCommentsView();
|
|
65689
|
-
}, 500);
|
|
66789
|
+
showCommentsView();
|
|
65690
66790
|
} else {
|
|
65691
66791
|
console.error("loadCommentsform is not a function");
|
|
65692
66792
|
}
|
|
@@ -65730,7 +66830,6 @@ function FormOnSave() {
|
|
|
65730
66830
|
completionPercentage: calculationPercentage,
|
|
65731
66831
|
},
|
|
65732
66832
|
});
|
|
65733
|
-
FormOnBackNavigation();
|
|
65734
66833
|
},
|
|
65735
66834
|
},
|
|
65736
66835
|
{
|
|
@@ -65774,6 +66873,58 @@ function setImageData(imageData, id, fileName) {
|
|
|
65774
66873
|
}
|
|
65775
66874
|
|
|
65776
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
|
+
|
|
65777
66928
|
window.loadComments = loadComments;
|
|
65778
66929
|
window.loadRNform = loadRNform;
|
|
65779
66930
|
window.FormOnSave = FormOnSave;
|
|
@@ -65782,6 +66933,9 @@ window.setImageData = setImageData;
|
|
|
65782
66933
|
window.FormOnSubmit = FormOnSubmit;
|
|
65783
66934
|
window.resetFormCache = resetFormCache;
|
|
65784
66935
|
|
|
66936
|
+
// Notify that loadRNform is ready (for event-based coordination)
|
|
66937
|
+
document.dispatchEvent(new CustomEvent('LoadRNformReady'));
|
|
66938
|
+
|
|
65785
66939
|
})();
|
|
65786
66940
|
|
|
65787
66941
|
// === SCRIPT_SEPARATOR ===
|
|
@@ -65837,7 +66991,7 @@ async function loadCommentsform(
|
|
|
65837
66991
|
window.formObj.nosubmit = true;
|
|
65838
66992
|
|
|
65839
66993
|
// Listen to form changes (optional, currently empty)
|
|
65840
|
-
window.formObj.on("change", () => {});
|
|
66994
|
+
window.formObj.on("change", () => { });
|
|
65841
66995
|
|
|
65842
66996
|
// Initialize Recogito and store globally
|
|
65843
66997
|
window.commentsResponse = Recogito.init({
|
|
@@ -65861,8 +67015,8 @@ async function loadCommentsform(
|
|
|
65861
67015
|
});
|
|
65862
67016
|
|
|
65863
67017
|
// Event listeners
|
|
65864
|
-
window.commentsResponse.on("createAnnotation", function (annotation) {});
|
|
65865
|
-
window.commentsResponse.on("updateAnnotation", function (annotation) {});
|
|
67018
|
+
window.commentsResponse.on("createAnnotation", function (annotation) { });
|
|
67019
|
+
window.commentsResponse.on("updateAnnotation", function (annotation) { });
|
|
65866
67020
|
window.commentsResponse.on("selectAnnotation", function (annotation) {
|
|
65867
67021
|
const eventCustom = new CustomEvent("annotateCss", { detail: true });
|
|
65868
67022
|
document.dispatchEvent(eventCustom);
|
|
@@ -65913,6 +67067,13 @@ async function goToformRender() {
|
|
|
65913
67067
|
}
|
|
65914
67068
|
} catch (e) {
|
|
65915
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
|
+
}
|
|
65916
67077
|
}
|
|
65917
67078
|
} else {
|
|
65918
67079
|
console.error("loadRNform is not defined");
|
|
@@ -65985,71 +67146,118 @@ window.CommentOnBack = CommentOnBack;
|
|
|
65985
67146
|
|
|
65986
67147
|
// Click outside handler for tooltip
|
|
65987
67148
|
document.addEventListener('click', function (event) {
|
|
65988
|
-
const moreBtn = document.getElementById('
|
|
67149
|
+
const moreBtn = document.getElementById('unvired-more-btn');
|
|
65989
67150
|
const tooltip = document.getElementById('moreTooltip');
|
|
65990
67151
|
if (moreBtn && tooltip && !moreBtn.contains(event.target) && !tooltip.contains(event.target)) {
|
|
65991
67152
|
tooltip.style.display = 'none';
|
|
65992
67153
|
}
|
|
65993
67154
|
});
|
|
65994
|
-
`.split(
|
|
65995
|
-
|
|
65996
|
-
|
|
65997
|
-
|
|
65998
|
-
|
|
65999
|
-
|
|
66000
|
-
|
|
66001
|
-
|
|
66002
|
-
|
|
66003
|
-
|
|
66004
|
-
|
|
66005
|
-
|
|
66006
|
-
|
|
66007
|
-
|
|
66008
|
-
|
|
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);
|
|
66009
67198
|
}
|
|
66010
|
-
};
|
|
66011
|
-
if (formioScript.onload !== void 0) {
|
|
66012
|
-
formioScript.onload = checkFormio;
|
|
66013
|
-
} else {
|
|
66014
|
-
checkFormio();
|
|
66015
67199
|
}
|
|
66016
|
-
|
|
66017
|
-
|
|
66018
|
-
|
|
66019
|
-
|
|
66020
|
-
|
|
66021
|
-
|
|
66022
|
-
}
|
|
66023
|
-
|
|
66024
|
-
|
|
66025
|
-
|
|
66026
|
-
|
|
66027
|
-
|
|
66028
|
-
|
|
66029
|
-
|
|
66030
|
-
|
|
66031
|
-
|
|
66032
|
-
|
|
66033
|
-
|
|
66034
|
-
|
|
66035
|
-
|
|
66036
|
-
|
|
66037
|
-
|
|
66038
|
-
|
|
66039
|
-
|
|
66040
|
-
|
|
66041
|
-
|
|
66042
|
-
|
|
66043
|
-
|
|
66044
|
-
|
|
66045
|
-
|
|
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");
|
|
66046
67247
|
}
|
|
66047
|
-
|
|
66048
|
-
|
|
66049
|
-
|
|
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);
|
|
66050
67258
|
}
|
|
67259
|
+
console.log("\u2705 Formio verified (previously loaded)");
|
|
66051
67260
|
}
|
|
66052
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
66053
67261
|
window.FORM_TEMPLATE = mergedWithMasterData;
|
|
66054
67262
|
window.FORM_PREVIOUS_DATA = submissionData;
|
|
66055
67263
|
window.FORM_MODE = options.mode;
|
|
@@ -66061,6 +67269,7 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66061
67269
|
window.FORM_ENV = options.environmentVariable;
|
|
66062
67270
|
window.FORM_THEME_DATA = options.themeData;
|
|
66063
67271
|
window.FORM_USER_DATA = options.userData;
|
|
67272
|
+
window.FORM_USERS_LIST = options.usersList;
|
|
66064
67273
|
window.FORM_CONTROL_DATA = options.controlData;
|
|
66065
67274
|
window.FORM_PRIVATE_EXTERNAL = options.privateExternal;
|
|
66066
67275
|
window.FORM_PERMISSION = options.permission;
|
|
@@ -66075,13 +67284,18 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66075
67284
|
ONCHANGE: "FORM_ONCHANGE"
|
|
66076
67285
|
};
|
|
66077
67286
|
const backBtn = container.querySelector("#form-back-btn");
|
|
66078
|
-
const moreBtn = container.querySelector("#
|
|
67287
|
+
const moreBtn = container.querySelector("#unvired-more-btn");
|
|
66079
67288
|
if (backBtn) {
|
|
66080
67289
|
backBtn.style.display = options.showBackButton ? "inline-block" : "none";
|
|
66081
67290
|
}
|
|
66082
67291
|
if (moreBtn && !options.showMoreButton) {
|
|
66083
67292
|
moreBtn.style.display = "none";
|
|
66084
67293
|
}
|
|
67294
|
+
window.__unviredFormsOptions = options;
|
|
67295
|
+
window.checkDocumentsVisibility();
|
|
67296
|
+
if (typeof window.checkMoreButtonVisibility === "function") {
|
|
67297
|
+
window.checkMoreButtonVisibility();
|
|
67298
|
+
}
|
|
66085
67299
|
if (options.platform === "web") {
|
|
66086
67300
|
window.platform = { isBrowser: true, isAndroid: false, iosPlatform: false };
|
|
66087
67301
|
} else if (options.platform === "android") {
|
|
@@ -66119,6 +67333,8 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66119
67333
|
if (options.language) window.FORMIO_LANGUAGE = options.language;
|
|
66120
67334
|
if (options.translations) window.FORMIO_I18N = options.translations;
|
|
66121
67335
|
if (options.userData) {
|
|
67336
|
+
window.firstName = options.userData.firstName;
|
|
67337
|
+
window.lastName = options.userData.lastName;
|
|
66122
67338
|
window.form = window.form || {};
|
|
66123
67339
|
Object.assign(window.form, options.userData);
|
|
66124
67340
|
}
|
|
@@ -66136,59 +67352,38 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66136
67352
|
sendEventCallback2
|
|
66137
67353
|
);
|
|
66138
67354
|
}
|
|
66139
|
-
|
|
66140
|
-
|
|
66141
|
-
|
|
66142
|
-
|
|
66143
|
-
|
|
66144
|
-
|
|
66145
|
-
|
|
66146
|
-
|
|
66147
|
-
|
|
66148
|
-
|
|
66149
|
-
|
|
66150
|
-
|
|
66151
|
-
|
|
66152
|
-
|
|
66153
|
-
|
|
66154
|
-
);
|
|
66155
|
-
if (loaderElement && window.formObj) {
|
|
66156
|
-
window.formObj.formReady.then(() => {
|
|
66157
|
-
if (loaderElement) {
|
|
66158
|
-
loaderElement.classList.add("hidden");
|
|
66159
|
-
setTimeout(() => {
|
|
66160
|
-
if (loaderElement && loaderElement.parentNode) {
|
|
66161
|
-
loaderElement.parentNode.removeChild(loaderElement);
|
|
66162
|
-
}
|
|
66163
|
-
}, 400);
|
|
66164
|
-
}
|
|
66165
|
-
}).catch(() => {
|
|
66166
|
-
setTimeout(() => {
|
|
66167
|
-
if (loaderElement) {
|
|
66168
|
-
loaderElement.classList.add("hidden");
|
|
66169
|
-
setTimeout(() => {
|
|
66170
|
-
if (loaderElement && loaderElement.parentNode) {
|
|
66171
|
-
loaderElement.parentNode.removeChild(loaderElement);
|
|
66172
|
-
}
|
|
66173
|
-
}, 400);
|
|
66174
|
-
}
|
|
66175
|
-
}, 2e3);
|
|
66176
|
-
});
|
|
66177
|
-
}
|
|
66178
|
-
} else if (attempts < maxAttempts) {
|
|
66179
|
-
attempts++;
|
|
66180
|
-
console.log(`Waiting for loadRNform... attempt ${attempts}`);
|
|
66181
|
-
setTimeout(waitForLoadRNform, 500);
|
|
66182
|
-
} else {
|
|
66183
|
-
console.error("window.loadRNform is not defined after waiting", {
|
|
66184
|
-
availableFunctions: Object.keys(window).filter((key) => typeof window[key] === "function")
|
|
66185
|
-
});
|
|
66186
|
-
if (loaderElement) {
|
|
66187
|
-
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();
|
|
66188
67370
|
}
|
|
66189
|
-
}
|
|
66190
|
-
}
|
|
66191
|
-
|
|
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
|
+
);
|
|
66192
67387
|
return {
|
|
66193
67388
|
sendAction: (action) => {
|
|
66194
67389
|
var _a2;
|
|
@@ -66206,6 +67401,51 @@ window.CommentOnBack = CommentOnBack;
|
|
|
66206
67401
|
}
|
|
66207
67402
|
};
|
|
66208
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;
|
|
66209
67449
|
export {
|
|
66210
67450
|
loadUnviredForms
|
|
66211
67451
|
};
|