|
467 | 467 | * Setup event listeners for conditional logic evaluation. |
468 | 468 | */ |
469 | 469 | setupConditionalListeners() { |
470 | | - const formInputs = document.querySelectorAll( |
471 | | - '.openfields-meta-box input, .openfields-meta-box select, .openfields-meta-box textarea' |
472 | | - ); |
| 470 | + // Use event delegation on meta-box wrapper so new repeater rows trigger updates too |
| 471 | + const metaBox = document.querySelector('.openfields-meta-box'); |
| 472 | + if (!metaBox) return; |
| 473 | + |
| 474 | + // Single listener on parent element catches all bubbling change/input events |
| 475 | + metaBox.addEventListener('change', (e) => { |
| 476 | + // Check if this is a field input that should trigger conditional evaluation |
| 477 | + const target = e.target; |
| 478 | + if (this.isFieldInput(target)) { |
| 479 | + this.evaluateAllConditions(); |
| 480 | + } |
| 481 | + }, true); // Use capture phase to catch all events |
473 | 482 |
|
474 | | - formInputs.forEach(input => { |
475 | | - // Skip if already initialized to prevent duplicate event listeners. |
476 | | - if (input.dataset.ofConditionalInitialized) { |
477 | | - return; |
| 483 | + metaBox.addEventListener('input', (e) => { |
| 484 | + const target = e.target; |
| 485 | + if (this.isFieldInput(target)) { |
| 486 | + this.evaluateAllConditions(); |
478 | 487 | } |
479 | | - input.dataset.ofConditionalInitialized = 'true'; |
| 488 | + }, true); // Use capture phase |
| 489 | + }, |
480 | 490 |
|
481 | | - input.addEventListener('change', () => this.evaluateAllConditions()); |
482 | | - input.addEventListener('input', () => this.evaluateAllConditions()); |
483 | | - }); |
| 491 | + /** |
| 492 | + * Check if an element is a field input that should trigger conditional evaluation. |
| 493 | + * |
| 494 | + * @param {HTMLElement} element - The element to check. |
| 495 | + * @returns {boolean} Whether this is a field input. |
| 496 | + */ |
| 497 | + isFieldInput(element) { |
| 498 | + // Check if it's an input, select, or textarea |
| 499 | + if (!element || !element.tagName) return false; |
| 500 | + |
| 501 | + const tag = element.tagName.toLowerCase(); |
| 502 | + if (['input', 'select', 'textarea'].includes(tag)) { |
| 503 | + return true; |
| 504 | + } |
| 505 | + |
| 506 | + // Check if it's a switch or custom field input |
| 507 | + if (element.classList && ( |
| 508 | + element.classList.contains('openfields-switch-checkbox') || |
| 509 | + element.classList.contains('openfields-toggle-input') || |
| 510 | + element.classList.contains('openfields-field-input') |
| 511 | + )) { |
| 512 | + return true; |
| 513 | + } |
| 514 | + |
| 515 | + return false; |
484 | 516 | }, |
485 | 517 |
|
486 | 518 | /** |
|
568 | 600 |
|
569 | 601 | // rule.field is now a FIELD ID (immutable UUID/identifier) |
570 | 602 | // Look for any field with data-field-id attribute matching this ID |
571 | | - // This works for: root fields, repeater subfields, group subfields, anywhere |
| 603 | + // This works for: root fields, repeater subfields, group subfields, anywhere in the DOM |
572 | 604 | const fieldId = rule.field; |
573 | 605 | let fieldElement = document.querySelector(`[data-field-id="${fieldId}"]`); |
574 | 606 |
|
| 607 | + if (fieldElement) { |
| 608 | + // Found by field ID - this is the preferred method |
| 609 | + // Look for the actual input element within this wrapper |
| 610 | + const input = fieldElement.querySelector('input, select, textarea'); |
| 611 | + if (input) { |
| 612 | + fieldElement = input; |
| 613 | + } |
| 614 | + } |
| 615 | + |
575 | 616 | // Fallback: try to find by field name (backwards compatibility) |
| 617 | + // This is for fields created before data-field-id was implemented |
576 | 618 | if (!fieldElement) { |
577 | 619 | const fieldName = rule.field; |
578 | 620 | fieldElement = document.querySelector( |
|
584 | 626 |
|
585 | 627 | if (!fieldElement) { |
586 | 628 | console.warn(`[OpenFields] Conditional field not found: ${fieldId}`); |
587 | | - return true; // If field not found, don't block. |
| 629 | + return true; // If field not found, don't block (assume condition passes). |
588 | 630 | } |
589 | 631 |
|
590 | 632 | const currentValue = this.getFieldValue(fieldElement); |
|
0 commit comments