create-prisma-php-app 1.12.0 → 1.12.1
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/dist/src/Lib/FormHandler.php +1 -553
- package/package.json +1 -1
|
@@ -311,13 +311,7 @@ class FormHandler
|
|
|
311
311
|
{
|
|
312
312
|
$attribute = '';
|
|
313
313
|
$ruleParam = $ruleValue;
|
|
314
|
-
$
|
|
315
|
-
// $ruleParam = is_array($ruleValue) ? $ruleValue['value'] : $ruleValue;
|
|
316
|
-
|
|
317
|
-
if (is_array($ruleValue)) {
|
|
318
|
-
$ruleParam = $ruleValue['value'];
|
|
319
|
-
$requestName = $ruleValue['name'] ?? null;
|
|
320
|
-
}
|
|
314
|
+
$ruleParam = is_array($ruleValue) ? $ruleValue['value'] : $ruleValue;
|
|
321
315
|
|
|
322
316
|
switch ($rule) {
|
|
323
317
|
case 'text':
|
|
@@ -387,27 +381,6 @@ class FormHandler
|
|
|
387
381
|
case 'list':
|
|
388
382
|
$attribute .= " list='$ruleParam'";
|
|
389
383
|
break;
|
|
390
|
-
case 'create':
|
|
391
|
-
$attribute .= " data-url='$ruleParam' data-request-name='$requestName' data-request-type='create' data-type='register'";
|
|
392
|
-
break;
|
|
393
|
-
case 'read':
|
|
394
|
-
$attribute .= " data-url='$ruleParam' data-request-name='$requestName' data-request-type='read' data-type='register'";
|
|
395
|
-
break;
|
|
396
|
-
case 'update':
|
|
397
|
-
$attribute .= " data-url='$ruleParam' data-request-name='$requestName' data-request-type='update' data-type='register'";
|
|
398
|
-
break;
|
|
399
|
-
case 'delete':
|
|
400
|
-
$attribute .= " data-url='$ruleParam' data-request-name='$requestName' data-request-type='delete' data-type='register'";
|
|
401
|
-
break;
|
|
402
|
-
case 'event':
|
|
403
|
-
$attribute .= " data-event='$ruleParam' data-type='register'";
|
|
404
|
-
break;
|
|
405
|
-
case 'debounce':
|
|
406
|
-
$attribute .= " data-debounce='$ruleParam' data-type='register'";
|
|
407
|
-
break;
|
|
408
|
-
case 'templateConnect':
|
|
409
|
-
$attribute .= " data-template-connect='$ruleParam' data-type='register'";
|
|
410
|
-
break;
|
|
411
384
|
default:
|
|
412
385
|
// Optionally handle unknown rules or log them
|
|
413
386
|
break;
|
|
@@ -437,126 +410,6 @@ class FormHandler
|
|
|
437
410
|
$fieldData = $this->data[$field] ?? '';
|
|
438
411
|
return "id='fh-watch-$field' data-watch-value='$fieldData' data-type='watch'";
|
|
439
412
|
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Creates a template element for a form field.
|
|
443
|
-
*
|
|
444
|
-
* This function returns an HTML string for a template element with specified data attributes,
|
|
445
|
-
* useful for creating dynamic content that can be cloned and inserted into the DOM.
|
|
446
|
-
*
|
|
447
|
-
* @param array $params An associative array of parameters.
|
|
448
|
-
* - 'field' (optional): The name of the field to create a template for. If not provided, a generic template is created.
|
|
449
|
-
* - 'readOnLoad' (optional): A flag indicating whether the template should include the `data-read-on-load` attribute. Defaults to `true`.
|
|
450
|
-
* - 'listen' (optional): A string specifying any event the template should listen to. Defaults to an empty string.
|
|
451
|
-
* - 'noCache' (optional): A flag indicating whether the template should include the `data-no-cache` attribute. Defaults to `false`.
|
|
452
|
-
*
|
|
453
|
-
* @return string An HTML string with data attributes for the template. If a field name is provided,
|
|
454
|
-
* it includes the `data-template-field` attribute. Otherwise, it includes the `data-template-general` attribute.
|
|
455
|
-
*
|
|
456
|
-
* @example
|
|
457
|
-
* Example usage to create a template element for a "user" field:
|
|
458
|
-
*
|
|
459
|
-
* $params = [
|
|
460
|
-
* 'field' => 'user',
|
|
461
|
-
* 'readOnLoad' => true,
|
|
462
|
-
* 'listen' => 'exampleEvent',
|
|
463
|
-
* 'noCache' => true
|
|
464
|
-
* ];
|
|
465
|
-
* echo $form->template($params);
|
|
466
|
-
* Output: "data-template-field='user' data-read-on-load='1' data-type='template' data-listen='exampleEvent' data-no-cache='1'"
|
|
467
|
-
*
|
|
468
|
-
* Example usage to create a generic template element:
|
|
469
|
-
*
|
|
470
|
-
* $params = [
|
|
471
|
-
* 'readOnLoad' => true,
|
|
472
|
-
* 'listen' => 'exampleEvent',
|
|
473
|
-
* 'noCache' => false
|
|
474
|
-
* ];
|
|
475
|
-
* echo $form->template($params);
|
|
476
|
-
* Output: "data-template-general='true' data-read-on-load='1' data-type='template' data-listen='exampleEvent' data-no-cache='0'"
|
|
477
|
-
*/
|
|
478
|
-
public function template(array $params = []): string
|
|
479
|
-
{
|
|
480
|
-
$field = isset($params['field']) ? Validator::validateString($params['field']) : null;
|
|
481
|
-
$readOnLoad = isset($params['readOnLoad']) ? Validator::validateBoolean($params['readOnLoad']) : true;
|
|
482
|
-
$listen = isset($params['listen']) ? Validator::validateString($params['listen']) : '';
|
|
483
|
-
$noCache = isset($params['noCache']) ? Validator::validateBoolean($params['noCache']) : false;
|
|
484
|
-
if ($field) {
|
|
485
|
-
$templateData = "data-template-field='$field' data-read-on-load='$readOnLoad' data-type='template' data-listen='$listen' data-no-cache='$noCache'";
|
|
486
|
-
} else {
|
|
487
|
-
$templateData = "data-template-general='true' data-read-on-load='$readOnLoad' data-type='template' data-listen='$listen' data-no-cache='$noCache'";
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
return $templateData;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* Creates a template placeholder for a form field.
|
|
495
|
-
*
|
|
496
|
-
* This function returns a `data-template-placeholder` attribute with the field name as the value,
|
|
497
|
-
*
|
|
498
|
-
* useful for dynamically populating template elements with field data.
|
|
499
|
-
*
|
|
500
|
-
* @param string $field The name of the field to create a placeholder for.
|
|
501
|
-
*
|
|
502
|
-
* @return string A `data-template-placeholder` attribute with the field name as the value.
|
|
503
|
-
*
|
|
504
|
-
* @example
|
|
505
|
-
* Example usage to create a placeholder for a "name" field:
|
|
506
|
-
* echo $form->templatePlaceholder('name');
|
|
507
|
-
* This will generate: "data-template-placeholder='name'"
|
|
508
|
-
*/
|
|
509
|
-
public function templatePlaceholder(string $field)
|
|
510
|
-
{
|
|
511
|
-
$field = Validator::validateString($field);
|
|
512
|
-
return "data-template-placeholder='$field' data-type='template-placeholder'";
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Generates a string containing data attributes for a button element based on input parameters.
|
|
517
|
-
*
|
|
518
|
-
* This function accepts an associative array where keys are attribute names (without the 'data-' prefix)
|
|
519
|
-
* and values are the attribute values. It will only add an attribute if the associated value is not empty.
|
|
520
|
-
*
|
|
521
|
-
* @param array $attributes Associative array with the following keys and their corresponding values:
|
|
522
|
-
* - 'info': Information for the `data-info` attribute.
|
|
523
|
-
* - 'event': Event-handler pairs formatted as a string for the `data-event` attribute.
|
|
524
|
-
* - 'formAction': Actions or operations associated with a form for the `data-form` attribute.
|
|
525
|
-
* - 'connect': Additional connections related to the button for the `data-connect` attribute.
|
|
526
|
-
*
|
|
527
|
-
* @return string A string containing the concatenated `data-*` attributes, ready for inclusion in an HTML tag.
|
|
528
|
-
*
|
|
529
|
-
* @throws InvalidArgumentException If any value in the array does not pass validation.
|
|
530
|
-
*/
|
|
531
|
-
public function event(array $attributes)
|
|
532
|
-
{
|
|
533
|
-
$dataAttributes = [];
|
|
534
|
-
$possibleAttributes = ['info', 'event', 'form', 'connect'];
|
|
535
|
-
|
|
536
|
-
foreach ($possibleAttributes as $attr) {
|
|
537
|
-
if (isset($attributes[$attr]) && $attributes[$attr] !== '') {
|
|
538
|
-
$validatedValue = Validator::validateString($attributes[$attr]);
|
|
539
|
-
$dataAttributes[] = "data-$attr='$validatedValue' data-type='event'";
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
return implode(' ', $dataAttributes);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
public function templateConnect(string $field)
|
|
547
|
-
{
|
|
548
|
-
$field = Validator::validateString($field);
|
|
549
|
-
return "data-template-connect='$field' data-type='template-connect'";
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
public function form(string $field, ...$options)
|
|
553
|
-
{
|
|
554
|
-
$field = Validator::validateString($field);
|
|
555
|
-
$attributes = "id='fh-form-$field' method='post'";
|
|
556
|
-
$optionsAttributes = json_encode($options);
|
|
557
|
-
$attributes .= " data-options='$optionsAttributes' data-type='form'";
|
|
558
|
-
return $attributes;
|
|
559
|
-
}
|
|
560
413
|
}
|
|
561
414
|
|
|
562
415
|
?>
|
|
@@ -565,9 +418,7 @@ class FormHandler
|
|
|
565
418
|
class FormHandler {
|
|
566
419
|
constructor() {
|
|
567
420
|
this.errors = [];
|
|
568
|
-
this.requestCache = new Map();
|
|
569
421
|
this.dataRulesElements = document.querySelectorAll('[data-rules]');
|
|
570
|
-
this.dataFormElements = document.querySelectorAll('[data-type="form"]');
|
|
571
422
|
this.init();
|
|
572
423
|
}
|
|
573
424
|
|
|
@@ -575,12 +426,6 @@ class FormHandler
|
|
|
575
426
|
this.dataRulesElements.forEach(fieldElement => {
|
|
576
427
|
this.initializeFieldFromDOM(fieldElement);
|
|
577
428
|
});
|
|
578
|
-
|
|
579
|
-
this.dataFormElements.forEach(formElement => {
|
|
580
|
-
this.initializeFormFromDOM(formElement);
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
this.event();
|
|
584
429
|
}
|
|
585
430
|
|
|
586
431
|
initializeFieldFromDOM(fieldElement) {
|
|
@@ -590,26 +435,7 @@ class FormHandler
|
|
|
590
435
|
}
|
|
591
436
|
|
|
592
437
|
const fieldName = fieldElement.name;
|
|
593
|
-
const dataUrl = fieldElement.getAttribute('data-url');
|
|
594
438
|
const rules = JSON.parse(fieldElement.getAttribute('data-rules') || '{}');
|
|
595
|
-
const event = fieldElement.getAttribute('data-event');
|
|
596
|
-
|
|
597
|
-
let debounceTime = fieldElement.getAttribute('data-debounce');
|
|
598
|
-
if (!debounceTime || debounceTime.length < 1) {
|
|
599
|
-
debounceTime = 300;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const debouncedInputHandler = debounce(async () => {
|
|
603
|
-
if (dataUrl) {
|
|
604
|
-
if (fieldElement.getAttribute('data-type') === 'register') {
|
|
605
|
-
if (fieldElement.getAttribute('data-request-type') === 'read') {
|
|
606
|
-
await this.read(dataUrl, fieldElement).catch(error => {
|
|
607
|
-
console.error("Read failed for field", fieldName, error);
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}, debounceTime);
|
|
613
439
|
|
|
614
440
|
const immediateObserver = (e) => {
|
|
615
441
|
const target = e.target;
|
|
@@ -622,113 +448,7 @@ class FormHandler
|
|
|
622
448
|
}
|
|
623
449
|
};
|
|
624
450
|
|
|
625
|
-
fieldElement.addEventListener('input', debouncedInputHandler);
|
|
626
451
|
fieldElement.addEventListener('input', immediateObserver);
|
|
627
|
-
|
|
628
|
-
if (dataUrl) {
|
|
629
|
-
if (this.isDataTypeExists(fieldElement, 'register')) {
|
|
630
|
-
if (fieldElement.getAttribute('data-request-type') === 'read') {
|
|
631
|
-
this.read(dataUrl, fieldElement).catch(error => {
|
|
632
|
-
console.error("Initial read failed for field", fieldName, error);
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
initializeFormFromDOM(formElement) {
|
|
640
|
-
if (!formElement) return;
|
|
641
|
-
|
|
642
|
-
formElement.addEventListener('submit', async (e) => {
|
|
643
|
-
e.preventDefault();
|
|
644
|
-
|
|
645
|
-
const formData = new FormData(formElement);
|
|
646
|
-
const formFields = Object.fromEntries(formData.entries());
|
|
647
|
-
|
|
648
|
-
const optionsAttribute = formElement.getAttribute('data-options');
|
|
649
|
-
if (!optionsAttribute) {
|
|
650
|
-
console.error("Missing 'data-options' attribute.");
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
let formOptions;
|
|
655
|
-
try {
|
|
656
|
-
formOptions = JSON.parse(optionsAttribute);
|
|
657
|
-
} catch (parseError) {
|
|
658
|
-
console.error("Failed to parse 'data-options'.", parseError);
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
const formAction = formElement.dataset.action;
|
|
663
|
-
const url = formOptions[0]?.[formAction];
|
|
664
|
-
const readFieldName = formOptions[0]?.['read'];
|
|
665
|
-
const field = document.getElementById(`fh-${readFieldName.name}`);
|
|
666
|
-
const finishFunctionName = formOptions[0]?.['finishFunction'];
|
|
667
|
-
|
|
668
|
-
if (!url) {
|
|
669
|
-
console.error(`Invalid form action: ${formAction}`);
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
const handleAction = async (actionFunc, errorMsg) => {
|
|
674
|
-
try {
|
|
675
|
-
await actionFunc(url, formFields);
|
|
676
|
-
} catch (error) {
|
|
677
|
-
console.error(errorMsg, error);
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
switch (formAction) {
|
|
682
|
-
case 'create':
|
|
683
|
-
await handleAction(this.create.bind(this), "Create failed");
|
|
684
|
-
break;
|
|
685
|
-
case 'update':
|
|
686
|
-
await handleAction(this.update.bind(this), "Update failed");
|
|
687
|
-
break;
|
|
688
|
-
case 'delete':
|
|
689
|
-
await handleAction(this.delete.bind(this), "Delete failed");
|
|
690
|
-
break;
|
|
691
|
-
default:
|
|
692
|
-
console.error(`Unknown action: ${formAction}`);
|
|
693
|
-
break;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
if (field) {
|
|
697
|
-
try {
|
|
698
|
-
await this.read(field.dataset.url, field);
|
|
699
|
-
} catch (error) {
|
|
700
|
-
console.error("Read failed", error);
|
|
701
|
-
}
|
|
702
|
-
} else {
|
|
703
|
-
if (readFieldName) {
|
|
704
|
-
try {
|
|
705
|
-
await this.read(readFieldName.url, {
|
|
706
|
-
name: readFieldName,
|
|
707
|
-
value: ''
|
|
708
|
-
});
|
|
709
|
-
} catch (error) {
|
|
710
|
-
console.error("Read failed", error);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
if (finishFunctionName && typeof window[finishFunctionName] === 'function') {
|
|
716
|
-
window[finishFunctionName]();
|
|
717
|
-
}
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
isDataTypeExists(element, dataType) {
|
|
722
|
-
return this.getDataTypes(element).includes(dataType);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
getDataTypes(element) {
|
|
726
|
-
const dataTypes = element.getAttribute('data-type');
|
|
727
|
-
if (dataTypes) {
|
|
728
|
-
return dataTypes.split(',').map(val => val.trim());
|
|
729
|
-
} else {
|
|
730
|
-
return [];
|
|
731
|
-
}
|
|
732
452
|
}
|
|
733
453
|
|
|
734
454
|
updateElementDisplay(displayElement, field) {
|
|
@@ -771,278 +491,6 @@ class FormHandler
|
|
|
771
491
|
}
|
|
772
492
|
}
|
|
773
493
|
|
|
774
|
-
event() {
|
|
775
|
-
const eventElements = document.querySelectorAll('[data-event]');
|
|
776
|
-
eventElements.forEach(element => {
|
|
777
|
-
const eventAttr = element.getAttribute('data-event');
|
|
778
|
-
if (eventAttr) {
|
|
779
|
-
const events = eventAttr.split(';');
|
|
780
|
-
events.forEach(eventFunctionPair => {
|
|
781
|
-
const [eventType, functionName] = eventFunctionPair.split(',').map(val => val.trim());
|
|
782
|
-
|
|
783
|
-
if (eventType && functionName && typeof window[functionName] === 'function') {
|
|
784
|
-
element.addEventListener(eventType, window[functionName]);
|
|
785
|
-
|
|
786
|
-
element.addEventListener(eventType, (e) => {
|
|
787
|
-
const eventForm = element.getAttribute('data-form');
|
|
788
|
-
if (eventForm) {
|
|
789
|
-
const formAttributes = eventForm.split(',');
|
|
790
|
-
const formElement = document.getElementById(`fh-form-${formAttributes[0]}`);
|
|
791
|
-
const formAction = formAttributes[1];
|
|
792
|
-
|
|
793
|
-
if (!formElement) return;
|
|
794
|
-
|
|
795
|
-
if (['create', 'read', 'update', 'delete'].includes(formAction)) {
|
|
796
|
-
formElement.dataset.action = formAction;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
if (formAction === 'create') {
|
|
800
|
-
const templateElements = document.querySelectorAll('[data-template-connect]');
|
|
801
|
-
templateElements.forEach(templateElement => {
|
|
802
|
-
if (templateElement) {
|
|
803
|
-
this.updateElementDisplay(templateElement, {
|
|
804
|
-
tagName: templateElement.tagName,
|
|
805
|
-
value: '',
|
|
806
|
-
textContent: ''
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
} else {
|
|
814
|
-
console.error(`Invalid event or function: ${eventFunctionPair}`);
|
|
815
|
-
}
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
getTemplateForField(field) {
|
|
822
|
-
let templates = [];
|
|
823
|
-
const typeTemplate = document.querySelectorAll('[data-type="template"]');
|
|
824
|
-
|
|
825
|
-
if (typeTemplate.length > 0) {
|
|
826
|
-
templates = Array.from(typeTemplate).filter(template => {
|
|
827
|
-
const templateField = template.getAttribute('data-template-field');
|
|
828
|
-
const generalTemplate = template.getAttribute('data-template-general');
|
|
829
|
-
const listen = template.getAttribute('data-listen');
|
|
830
|
-
if (templateField === field.name) {
|
|
831
|
-
return true;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const templateListener = document.querySelector(`[data-template-field="${listen}"]`);
|
|
835
|
-
if (templateListener && templateListener.getAttribute('data-listen') !== '') {
|
|
836
|
-
return true;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
if (listen === 'read') {
|
|
840
|
-
return true;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
if (generalTemplate === 'true') {
|
|
844
|
-
return true;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
return false;
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
return templates;
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
processDataItems(items, template, tbody) {
|
|
854
|
-
items.forEach((item) => {
|
|
855
|
-
const clone = document.importNode(template.content, true);
|
|
856
|
-
|
|
857
|
-
Object.keys(item).forEach(key => {
|
|
858
|
-
const placeholderElement = clone.querySelector(`[data-template-placeholder="${key}"]`);
|
|
859
|
-
if (placeholderElement) {
|
|
860
|
-
placeholderElement.textContent = item[key];
|
|
861
|
-
}
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
const dataInfoElements = clone.querySelectorAll('[data-info], [data-event], [data-connect]');
|
|
865
|
-
dataInfoElements.forEach(element => {
|
|
866
|
-
this.attachEventHandlers(element, item);
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
tbody.appendChild(clone);
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
attachEventHandlers(element, item) {
|
|
874
|
-
const infoKeys = element.getAttribute('data-info');
|
|
875
|
-
if (infoKeys) {
|
|
876
|
-
if (infoKeys === 'all') {
|
|
877
|
-
const keys = Object.keys(item);
|
|
878
|
-
keys.forEach(key => {
|
|
879
|
-
if (item[key] !== undefined) {
|
|
880
|
-
element.dataset[key] = item[key];
|
|
881
|
-
}
|
|
882
|
-
});
|
|
883
|
-
} else {
|
|
884
|
-
const keys = infoKeys.split(',').map(key => key.trim());
|
|
885
|
-
keys.forEach(key => {
|
|
886
|
-
if (item[key] !== undefined) {
|
|
887
|
-
element.dataset[key] = item[key];
|
|
888
|
-
}
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
const eventAttr = element.getAttribute('data-event');
|
|
894
|
-
if (eventAttr) {
|
|
895
|
-
const events = eventAttr.split(';');
|
|
896
|
-
events.forEach(eventFunctionPair => {
|
|
897
|
-
const [eventType, functionName] = eventFunctionPair.split(',').map(val => val.trim());
|
|
898
|
-
|
|
899
|
-
if (eventType && functionName && typeof window[functionName] === 'function') {
|
|
900
|
-
element.addEventListener(eventType, window[functionName]);
|
|
901
|
-
|
|
902
|
-
element.addEventListener(eventType, (e) => {
|
|
903
|
-
this.handleDataConnectAndFormActions(element, item);
|
|
904
|
-
});
|
|
905
|
-
} else {
|
|
906
|
-
console.error(`Invalid event or function: ${eventFunctionPair}`);
|
|
907
|
-
}
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
handleDataConnectAndFormActions(element, item) {
|
|
913
|
-
const eventForm = element.getAttribute('data-form');
|
|
914
|
-
if (eventForm) {
|
|
915
|
-
const formAttributes = eventForm.split(',');
|
|
916
|
-
const formElement = document.getElementById(`fh-form-${formAttributes[0]}`);
|
|
917
|
-
const formAction = formAttributes[1];
|
|
918
|
-
|
|
919
|
-
if (!formElement) return;
|
|
920
|
-
|
|
921
|
-
if (['create', 'read', 'update', 'delete'].includes(formAction)) {
|
|
922
|
-
formElement.dataset.action = formAction;
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
const templateConnectValues = element.getAttribute('data-connect');
|
|
927
|
-
if (templateConnectValues) {
|
|
928
|
-
const connectValues = templateConnectValues.split(',').map(value => value.trim());
|
|
929
|
-
connectValues.forEach(connectValue => {
|
|
930
|
-
const templateElements = document.querySelectorAll(`[data-template-connect="${connectValue}"]`);
|
|
931
|
-
templateElements.forEach(templateElement => {
|
|
932
|
-
this.updateElementDisplay(templateElement, {
|
|
933
|
-
tagName: templateElement.tagName,
|
|
934
|
-
value: item[connectValue],
|
|
935
|
-
textContent: item[connectValue]
|
|
936
|
-
});
|
|
937
|
-
});
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
updateTemplates(templates, response, field) {
|
|
943
|
-
const items = Array.isArray(response) ? response : [response];
|
|
944
|
-
templates.forEach(template => {
|
|
945
|
-
let readOnLoad = template.getAttribute('data-read-on-load');
|
|
946
|
-
let noCache = template.getAttribute('data-no-cache');
|
|
947
|
-
if (readOnLoad === '' && (field.value === undefined || field.value.length === 0)) {
|
|
948
|
-
const tbody = template.parentNode;
|
|
949
|
-
tbody.innerHTML = '';
|
|
950
|
-
tbody.appendChild(template);
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
const tbody = template.parentNode;
|
|
955
|
-
tbody.innerHTML = '';
|
|
956
|
-
tbody.appendChild(template);
|
|
957
|
-
|
|
958
|
-
this.processDataItems(items, template, tbody);
|
|
959
|
-
|
|
960
|
-
if (noCache !== '') {
|
|
961
|
-
this.requestCache.delete(cacheKey);
|
|
962
|
-
}
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
clearCache() {
|
|
967
|
-
this.requestCache.clear();
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
async create(url, data) {
|
|
971
|
-
if (!url || !data) return;
|
|
972
|
-
|
|
973
|
-
try {
|
|
974
|
-
const response = await api.post(url, data);
|
|
975
|
-
this.clearCache();
|
|
976
|
-
} catch (error) {
|
|
977
|
-
console.error("Create failed", error);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
async read(url, field) {
|
|
982
|
-
if (!url || !field) return;
|
|
983
|
-
|
|
984
|
-
let fieldDataName = '';
|
|
985
|
-
if (field instanceof HTMLElement) {
|
|
986
|
-
const requestName = field.getAttribute('data-request-name');
|
|
987
|
-
fieldDataName = requestName && requestName.length > 0 ? requestName : field.name;
|
|
988
|
-
} else {
|
|
989
|
-
fieldDataName = field.name ?? '';
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
if (!fieldDataName) return;
|
|
993
|
-
|
|
994
|
-
const data = {
|
|
995
|
-
[fieldDataName]: field.value
|
|
996
|
-
};
|
|
997
|
-
|
|
998
|
-
let templates = this.getTemplateForField(field);
|
|
999
|
-
if (templates.length === 0) return;
|
|
1000
|
-
|
|
1001
|
-
const cacheKey = `${url}-${JSON.stringify(data)}`;
|
|
1002
|
-
if (this.requestCache.has(cacheKey)) {
|
|
1003
|
-
return this.requestCache.get(cacheKey)
|
|
1004
|
-
.then(response => {
|
|
1005
|
-
this.updateTemplates(templates, response, field);
|
|
1006
|
-
})
|
|
1007
|
-
.catch(error => {
|
|
1008
|
-
console.error("🚀 ~ FormHandler ~ read ~ error from cache:", error);
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
const requestPromise = api.post(url, data);
|
|
1013
|
-
this.requestCache.set(cacheKey, requestPromise);
|
|
1014
|
-
|
|
1015
|
-
try {
|
|
1016
|
-
const response = await requestPromise;
|
|
1017
|
-
this.updateTemplates(templates, response, field, cacheKey);
|
|
1018
|
-
} catch (error) {
|
|
1019
|
-
console.error("🚀 ~ FormHandler ~ read ~ error from request:", error);
|
|
1020
|
-
this.requestCache.delete(cacheKey);
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
async update(url, data) {
|
|
1025
|
-
if (!url || !data) return;
|
|
1026
|
-
|
|
1027
|
-
try {
|
|
1028
|
-
const response = await api.put(url, data);
|
|
1029
|
-
this.clearCache();
|
|
1030
|
-
} catch (error) {
|
|
1031
|
-
console.error("Update failed", error);
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
async delete(url, data) {
|
|
1036
|
-
if (!url || !data) return;
|
|
1037
|
-
|
|
1038
|
-
try {
|
|
1039
|
-
const response = await api.delete(url, data);
|
|
1040
|
-
this.clearCache();
|
|
1041
|
-
} catch (error) {
|
|
1042
|
-
console.error("Delete failed", error);
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
494
|
validateField(field, value, rules) {
|
|
1047
495
|
if (!rules) return [];
|
|
1048
496
|
this.errors = [];
|