From ccf6b3afaa5eb29c70514af639c12da0475e799c Mon Sep 17 00:00:00 2001 From: Mykhailo Kulinich Date: Tue, 22 Oct 2024 00:40:00 +0300 Subject: [PATCH] ADD: repeater inner fields support --- assets/js/frontend.js | 81 ++++++++++++++++++++++--------- jet-form-builder-update-field.php | 4 +- rest-api/endpoint.php | 60 ++++++++++++++++++----- storage.php | 41 +++++++++++++--- 4 files changed, 144 insertions(+), 42 deletions(-) diff --git a/assets/js/frontend.js b/assets/js/frontend.js index 8fe4cc5..77205eb 100644 --- a/assets/js/frontend.js +++ b/assets/js/frontend.js @@ -21,8 +21,7 @@ 'jet.fb.input.makeReactive', 'jfb-update-field/on-observe', function( input ) { - - return; + if ( ! input.path || input.path.length < 2 ) { return; @@ -31,11 +30,12 @@ const observable = input.getRoot(), formId = observable.form.getFormId(), node = input.nodes[0], - updatedNode = node.closest( '[data-update-field-name]' ); + updatedNode = node.closest( '[data-update-field-name]' ), + path = input.path; setFieldWatcher( formId, input ); - updateFormField( updatedNode, input.root ); + triggerUpdate( input ); } ); @@ -104,12 +104,12 @@ const input = observable.getInput( key ); - setFieldWatcher( formId, input ); - if ( ! input || ! input.value || input.inputType === "repeater" ) { continue; } + setFieldWatcher( formId, input ); + triggerUpdate( input ); } @@ -150,6 +150,10 @@ function getFormValues( observable ) { + if ( observable?.parent?.root ) { + observable = observable.parent.root; + } + const formFields = observable.getInputs(), formId = observable.form ? observable.form.getFormId() : observable.parent.root.form.getFormId(); @@ -157,7 +161,12 @@ formFields.forEach( function( input ) { - if ( undefined === input?.value?.current || input.inputType === "repeater" ) { + if ( undefined === input?.value?.current ) { + return; + } + + if ( input.inputType === "repeater" ) { + formValues[ input.name ] = getRepeaterValue( input ); return; } @@ -173,6 +182,24 @@ } + function getRepeaterValue( input ) { + + if ( input?.inputType !== "repeater" ) { + return []; + } + + let result = []; + + input.value.current.forEach( function( observable, i ) { + observable.getInputs().forEach( function( input ) { + result[ i ] ??= {}; + result[ i ][ input.name ] = input.value.current; + } ); + } ); + + return result; + } + function styleCalculated( updatedCalculated, type = 'add' ) { if ( ! updatedCalculated ) { @@ -274,8 +301,8 @@ function updateFormField( updatedNode, observable, button = null ) { - const updated = updatedNode.dataset.updateFieldName, - updatedInput = observable.getInput( updated ); + let updated = updatedNode.dataset.updateFieldName, + updatedInput = observable.getInput( updated ); if ( ! updatedInput ) { return; @@ -286,14 +313,16 @@ updatedCalculated = observable.rootNode.querySelectorAll( `[data-formula*=${updated}]` ), cacheTime = updatedNode.dataset.updateCacheTimeout || 60; - if ( aborters[ updated + formId ] ) { - aborters[ updated + formId ].abort(); - delete aborters[ updated + formId ]; + let aUpdated = ! observable?.parent?.name ? updated : updatedInput.rawName; + + if ( aborters[ aUpdated + formId ] ) { + aborters[ aUpdated + formId ].abort(); + delete aborters[ aUpdated + formId ]; } let aborter = new AbortController(); - aborters[ updated + formId ] = aborter; + aborters[ aUpdated + formId ] = aborter; updatedNode.classList.add( 'jfb-updated-field' ); @@ -303,9 +332,11 @@ maybeClearInput( updatedInput ); - updatedInput.reporting.validityState.current = false; + if ( updatedInput?.reporting?.validityState ) { + updatedInput.reporting.validityState.current = false; + } - const hash = getHash( updated, formId, formFields ); + const hash = getHash( aUpdated, formId, formFields ); if ( cache.has( hash ) ) { const cached = cache.get( hash ); @@ -328,18 +359,20 @@ } } + let rUpdated = ! observable?.parent?.name ? updated : updatedInput.rawName; + wp.apiFetch( { method: 'post', path: '/jet-form-builder-update-field-addon/v1/get-field', data: { - "form_id" : formId, - "field_name" : updated, - "form_fields" : formFields, + "form_id": formId, + "field_name": rUpdated, + "form_fields": formFields, }, signal: aborter.signal, } ).then( ( response ) => { - if ( aborter !== aborters[ updated + formId ] ) { + if ( aborter !== aborters[ aUpdated + formId ] ) { return; } @@ -358,10 +391,10 @@ } ).catch( function ( e ) { - if ( aborter === aborters[ updated + formId ] ) { + if ( aborter === aborters[ aUpdated + formId ] ) { console.error( e ); - delete aborters[ updated + formId ]; + delete aborters[ aUpdated + formId ]; updatedNode.classList.remove( 'jfb-updated-field' ); @@ -376,7 +409,7 @@ function setFieldWatcher( formId, watchedField ) { - const observable = watchedField?.root || JetFormBuilder[ formId ]; + let observable = watchedField?.root || JetFormBuilder[ formId ]; if ( ! observable ) { return; @@ -392,6 +425,10 @@ watched = watchedField.name; } else if ( watched.includes('[') ) { watched = watched.replaceAll( /\[\d+\]\[/g, '[' ); + + if ( observable?.parent?.name ) { + watched = watched.replaceAll( observable.parent.name + '[', '[' ); + } } if ( ! watchedField?.value ) { diff --git a/jet-form-builder-update-field.php b/jet-form-builder-update-field.php index 65e1b62..f182288 100644 --- a/jet-form-builder-update-field.php +++ b/jet-form-builder-update-field.php @@ -3,7 +3,7 @@ * Plugin Name: JetFormBuilder - Update Fields * Plugin URI: * Description: - * Version: 1.1.3 + * Version: 1.2.0 * Author: * Author URI: * Text Domain: @@ -31,7 +31,7 @@ class Plugin { public $storage = null; - private $version = '1.1.3'; + private $version = '1.2.0'; public function __construct() { add_action( 'plugins_loaded', array( $this, 'jec_init' ) ); diff --git a/rest-api/endpoint.php b/rest-api/endpoint.php index ee07e9e..9602c36 100644 --- a/rest-api/endpoint.php +++ b/rest-api/endpoint.php @@ -58,24 +58,61 @@ public function get_support_type( $attrs ) { public function callback( $request ) { - $params = json_decode( $request->get_body() ); + $params = json_decode( $request->get_body(), true ); - $form_id = $params->form_id; - $field_name = $params->field_name; - $form_fields = ( array ) $params->form_fields; + $form_id = $params['form_id']; + $field_name = $params['field_name']; + $form_fields = $params['form_fields']; + + $storage = Plugin::instance()->storage; foreach ( $form_fields as $name => $value ) { $_REQUEST['jfb_update_related_' . $name] = $value; - Plugin::instance()->storage->save_field_value( $name, $value ); + $storage->save_field_value( $name, $value ); } + //setup form context $blocks = Block_Helper::get_blocks_by_post( $form_id ); + jet_fb_handler()->set_form_id( $form_id ); + jet_fb_context()->set_request( $form_fields ); + jet_fb_context()->apply( $blocks ); + + $is_repeater = preg_match( '/(?.+)\[(?\d+)\]\[(?.+)\]/', $field_name, $matches ); + + if ( $is_repeater ) { + $field_name = $matches['field_name']; + $sub_name = $matches['sub_name']; + $index = $matches['index']; + } $block = \Jet_Form_Builder\Blocks\Block_Helper::find_block_by_name( $field_name, $blocks ); + if ( $is_repeater && $block['blockName'] !== 'jet-forms/repeater-field' ) { + return array( + 'type' => 'error', + 'value' => 'This field does not have Field Updater enabled or its settings are invalid.', + ); + } + + if ( $is_repeater && ! empty( $block['innerBlocks'] ) ) { + foreach ( $block['innerBlocks'] as $inner_block ) { + if ( ! empty( $inner_block['attrs'] ) && $inner_block['attrs']['name'] === $sub_name ) { + $block = $inner_block; + } + } + + $storage->set_context( $field_name ); + $storage->set_index( $index ); + } + if ( ! empty( $block['attrs']['jfb_update_fields_value_enabled'] ) && $this->get_support_type( $block ) === 'value' ) { - $value = $this->get_value( $block['attrs'], $field_name, $form_id, $form_fields ); + $value = $this->get_value( + $block['attrs'], + $is_repeater ? $params->field_name : $field_name, + $form_id, + $form_fields + ); if ( empty( $value ) && isset( $block['attrs']['default'] ) ) { $value = $block['attrs']['default']; @@ -95,13 +132,14 @@ public function callback( $request ) { ); } - // set up block structure - jet_fb_context()->set_parsers( - $blocks - ); + if ( $is_repeater ) { + $field_path = array( $field_name, $index, $sub_name ); + } else { + $field_path = array( $field_name ); + } try { - $parser = jet_fb_context()->resolve_parser( $params->field_name ); + $parser = jet_fb_context()->resolve_parser( $field_path ); } catch ( Silence_Exception $exception ) { // field not found return array( 'error' => true ); diff --git a/storage.php b/storage.php index f508310..a1a08c9 100644 --- a/storage.php +++ b/storage.php @@ -9,14 +9,41 @@ class Storage { - private $form_fields = array(); + private $form_fields = array(); - public function save_field_value( $field_name, $value ) { - $this->form_fields[ $field_name ] = $value; - } + private $context = ''; + private $index = -1; - public function get_field_value( $field_name ) { - return $this->form_fields[ $field_name ] ?? ''; - } + public function set_context( $context ) { + $this->context = $context; + } + + public function set_index( $index ) { + $this->index = $index; + } + + public function save_field_value( $field_name, $value ) { + $this->form_fields[ $field_name ] = $value; + } + + public function get_values() { + return $this->form_fields; + } + + public function get_field_value( $field_name ) { + if ( preg_match( '/(?.+)\[(?\d+)\]\[(?.+)\]/', $field_name, $matches ) ) { + $field_name = $matches['field_name']; + $sub_name = $matches['sub_name']; + $index = $matches['index']; + + return $this->form_fields[ $field_name ][ $index ][ $sub_name ] ?? ''; + } + + if ( $this->context && $this->index >= 0 && preg_match( '/\[(?.+)\]/', $field_name, $matches ) ) { + return $this->form_fields[ $this->context ][ $this->index ][ $matches['sub_name'] ] ?? ''; + } + + return $this->form_fields[ $field_name ] ?? ''; + } }