// --------------------------------------------------------------------------------------------------------------------- // == File ../includes/page-form-builder/ajax/_out/bfb-ajax.js - after refactor 2026-02-28 15:14 rolback to this paoint, if something will go wrong. // --------------------------------------------------------------------------------------------------------------------- (function (w, d, $) { 'use strict'; var AjaxCfg = w.WPBC_BFB_Ajax || {}; if ( ! AjaxCfg.url ) { // Not on builder page or config not injected. return; } if ( ! $ || ! $.ajax ) { // In WP admin jQuery should exist; if not, stop to avoid silent corruption. wpbc_admin_show_message( 'WPBC BFB: jQuery is not available.', 'error', 10000 ); console.error( 'WPBC BFB: jQuery is not available.' ); return; } function get_save_source( cfg, btn ) { // priority: button attr -> global cfg -> default var v = ''; try { if ( btn && btn.getAttribute ) { v = btn.getAttribute( 'data-wpbc-bfb-save-source' ) || ''; } } catch ( e ) {} if ( ! v && cfg && cfg.save_source ) { v = cfg.save_source; } v = String( v || 'auto' ).toLowerCase(); if ( [ 'builder', 'advanced', 'auto' ].indexOf( v ) === -1 ) { v = 'builder'; } return v; } function read_advanced_mode_payload() { // best: API (syncs CodeMirror -> textarea) if ( w.wpbc_bfb_advanced_editor_api && typeof w.wpbc_bfb_advanced_editor_api.get_values === 'function' ) { try { return w.wpbc_bfb_advanced_editor_api.get_values(); } catch ( e ) {} } // fallback: read textareas directly (may be stale if CM not saved) var ta_form = d.getElementById( 'wpbc_bfb__advanced_form_editor' ); var ta_content = d.getElementById( 'wpbc_bfb__content_form_editor' ); return { advanced_form: ta_form ? String( ta_form.value || '' ) : '', content_form : ta_content ? String( ta_content.value || '' ) : '', is_dirty : false }; } function has_text( v ) { return !! ( v && String( v ).trim() ); } /** * Serialize values so payload matches previous XMLHttpRequest behavior: * - null/undefined => '' * - objects/arrays => JSON.stringify(...) * - everything else => String(...) * * @param {*} value * @return {string} */ function wpbc_bfb__serialize_post_value( value ) { if ( value === null || typeof value === 'undefined' ) { return ''; } if ( typeof value === 'object' ) { try { return JSON.stringify( value ); } catch ( e ) { return ''; } } return String( value ); } /** * Normalize payload to scalar strings so jQuery does not produce "[object Object]". * * @param {Object} raw_data * @return {Object} */ function wpbc_bfb__normalize_post_data( raw_data ) { var out = {}; raw_data = raw_data || {}; for ( var k in raw_data ) { if ( ! Object.prototype.hasOwnProperty.call( raw_data, k ) ) { continue; } out[ k ] = wpbc_bfb__serialize_post_value( raw_data[ k ] ); } return out; } /** * POST helper (jQuery only) returning jqXHR promise. * IMPORTANT: dataType:'text' so callers keep manual JSON.parse exactly as before. * * @param {string} url * @param {Object} payload * @return {jqXHR} */ function wpbc_bfb__ajax_post( url, payload ) { return $.ajax( { url : url, type : 'POST', data : wpbc_bfb__normalize_post_data( payload ), dataType : 'text', contentType : 'application/x-www-form-urlencoded; charset=UTF-8' } ); } /** * Safe JSON parse helper. * * @param {string} text * @return {Object|null} */ function wpbc_bfb__safe_json_parse( text ) { try { return JSON.parse( text ); } catch ( e ) { return null; } } /** * Parse combined length string like "100%", "320px", "12.5rem". * * @param {string} value * @return {{num:string, unit:string}} */ function parse_length_value( value ) { var raw = String( value == null ? '' : value ).trim(); var m = raw.match( /^\s*(-?\d+(?:\.\d+)?)\s*([a-z%]*)\s*$/i ); if ( ! m ) { return { num: raw, unit: '' }; } return { num: ( m[1] || '' ), unit: ( m[2] || '' ) }; } /** * SAVE: send current Builder structure (+ exported shortcodes) to PHP. * * Uses: * - WPBC_BFB_Ajax.url / nonce_save / form_name / engine / engine_version * - Optional WPBC_BFB_Exporter.export_all() * - Busy helpers wpbc_bfb__button_busy_start / _end if available. * * IMPORTANT: * - Local (form) settings are collected ONLY here (Save form), * via event "wpbc:bfb:form_settings:collect". */ function wpbc_bfb__ajax_save_current_form( btn, done_cb ) { var cfg = w.WPBC_BFB_Ajax || {}; var builder = w.wpbc_bfb || null; var $btn = btn ? $( btn ) : null; // --- Busy START ---------------------------------------------------------------------------------------------- if ( $btn && $btn.length ) { // Will read data-wpbc-u-busy-text="Saving..." from the and add spinner. if ( typeof w.wpbc_bfb__button_busy_start === 'function' ) { // FIX: guard w.wpbc_bfb__button_busy_start( $btn ); } else { $btn.prop( 'disabled', true ); } } else if ( btn ) { btn.disabled = true; } // --- Gather structure ---------------------------------------------------------------------------------------- var structure = ( builder && typeof builder.get_structure === 'function' ) ? builder.get_structure() : []; // --- Gather current form settings (event-based; modules can contribute) ------------------------------------- // ONLY supported settings format: // { // options : { key: value, ... }, // css_vars : [], // bfb_options : { advanced_mode_source: 'builder'|'advanced'|'auto' } // } var form_settings = { options : {}, css_vars : [], bfb_options : { advanced_mode_source: 'builder' } }; // Let Settings Options (and any other module) contribute local form settings. wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form_settings:collect', { settings : form_settings, form_name: cfg.form_name || 'standard' } ); // Normalize css_vars to array (schema enforcement). if ( form_settings && form_settings.css_vars && ! Array.isArray( form_settings.css_vars ) ) { var out = []; try { for ( var k in form_settings.css_vars ) { if ( Object.prototype.hasOwnProperty.call( form_settings.css_vars, k ) ) { out.push( { name: String( k ), value: String( form_settings.css_vars[ k ] ) } ); } } } catch ( _e0 ) {} form_settings.css_vars = out; } if ( ! form_settings.bfb_options || typeof form_settings.bfb_options !== 'object' ) { form_settings.bfb_options = { advanced_mode_source: 'builder' }; } if ( ! form_settings.bfb_options.advanced_mode_source ) { form_settings.bfb_options.advanced_mode_source = 'builder'; } var payload = { action : 'WPBC_AJX_BFB_SAVE_FORM_CONFIG', nonce : cfg.nonce_save || '', form_name : cfg.form_name || 'standard', engine : cfg.engine || 'bfb', engine_version: cfg.engine_version || '1.0', structure : JSON.stringify( structure ), settings : JSON.stringify( form_settings ) }; // ----------------------------------------------------------------------------- // Choose where advanced_form + content_form are taken from. // ----------------------------------------------------------------------------- var save_source = get_save_source( cfg, btn ); // 1) Try Advanced Mode text (if selected / auto+dirty). var adv = null; if ( save_source === 'advanced' || save_source === 'auto' ) { adv = read_advanced_mode_payload(); var can_use_advanced = ( save_source === 'advanced' ) || ( save_source === 'auto' && adv && adv.is_dirty ); if ( can_use_advanced ) { // If user forced "advanced" but both are empty -> fallback to exporter. if ( ! has_text( adv.advanced_form ) && ! has_text( adv.content_form ) ) { wpbc_admin_show_message( 'Advanced Mode is selected, but editors are empty. Using Builder export.', 'warning', 6000 ); } else { if ( has_text( adv.advanced_form ) ) { payload.advanced_form = adv.advanced_form; } if ( has_text( adv.content_form ) ) { payload.content_form = adv.content_form; } form_settings.bfb_options.advanced_mode_source = 'advanced'; payload.settings = JSON.stringify( form_settings ); // keep payload in sync. } } } // 2) If not taken from Advanced Mode -> export from Builder structure (current behavior). if ( ! payload.advanced_form || ! payload.content_form ) { if ( w.WPBC_BFB_Exporter && typeof w.WPBC_BFB_Exporter.export_all === 'function' ) { try { // Prefer Option A pack: settings.options.* var opt_pack = form_settings.options; var width_combined = opt_pack.booking_form_layout_width || ''; var parsed_width = parse_length_value( width_combined ); var export_options = { gapPercent : 3, form_slug : payload.form_name, form_width_value: parsed_width.num, form_width_unit : parsed_width.unit }; var export_result = w.WPBC_BFB_Exporter.export_all( structure || [], export_options ); if ( export_result ) { if ( ! payload.advanced_form && export_result.advanced_form ) { payload.advanced_form = export_result.advanced_form; } if ( ! payload.content_form && export_result.fields_data ) { payload.content_form = export_result.fields_data; } } form_settings.bfb_options.advanced_mode_source = 'builder'; payload.settings = JSON.stringify( form_settings ); // keep payload in sync. } catch ( e ) { wpbc_admin_show_message( 'WPBC BFB: export_all error', 'error', 10000 ); console.error( 'WPBC BFB: export_all error', e ); } } } // Update payload before send via AJAX, if needed. var hook_detail = { payload: payload }; wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:before_save_payload', hook_detail ); payload = hook_detail.payload; var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload ); ajax_request .done( function ( response_text, _text_status, jqxhr ) { // Keep old behavior: only treat exact 200 as success. if ( ! jqxhr || jqxhr.status !== 200 ) { if ( typeof done_cb === 'function' ) { try { done_cb( false, null ); } catch ( _e1 ) {} } wpbc_admin_show_message( 'WPBC BFB: save HTTP error', 'error', 10000 ); console.error( 'WPBC BFB: save HTTP error', jqxhr ? jqxhr.status : 0 ); return; } var resp = wpbc_bfb__safe_json_parse( response_text ); if ( ! resp ) { wpbc_admin_show_message( 'WPBC BFB: save JSON parse error', 'error', 10000 ); console.error( 'WPBC BFB: save JSON parse error', response_text ); return; } if ( ! resp || ! resp.success ) { const error_message = ( resp.data && resp.data.message ) ? resp.data.message : ''; wpbc_admin_show_message( 'WPBC BFB: save failed.' + ' | ' + error_message, 'error', 10000 ); console.error( 'WPBC BFB: save failed', resp ); return; } if ( typeof done_cb === 'function' ) { try { done_cb( true, resp ); } catch ( _e2 ) {} } wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:ajax_saved', { loaded_data: resp.data, form_name : cfg.form_name || 'standard' } ); // Optional: visual feedback. wpbc_admin_show_message( 'Form saved', 'success', 1000, false ); } ) .fail( function ( jqxhr ) { // Old behavior: status != 200 triggers done_cb(false, null). if ( typeof done_cb === 'function' ) { try { done_cb( false, null ); } catch ( _e3 ) {} } wpbc_admin_show_message( 'WPBC BFB: save HTTP error', 'error', 10000 ); console.error( 'WPBC BFB: save HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText ); } ) .always( function () { // --- Busy END (always) ---------------------------------------------------------------------------------- if ( $btn && $btn.length && typeof w.wpbc_bfb__button_busy_end === 'function' ) { w.wpbc_bfb__button_busy_end( $btn ); } else if ( $btn && $btn.length ) { $btn.prop( 'disabled', false ).removeClass( 'wpbc-is-busy' ); } else if ( btn ) { btn.disabled = false; } } ); } function apply_advanced_mode_texts( advanced_form, content_form, advanced_mode_source ) { var af = ( advanced_form == null ) ? '' : String( advanced_form ); var cf = ( content_form == null ) ? '' : String( content_form ); // Always update underlying