PluginProbe
Booking Calendar / 11.2.1
Booking Calendar v11.2.1
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
booking / includes / page-form-builder / ajax / _src / bfb-ajax.js

bfb-ajax.js in Booking Calendar 11.2.1, at includes/page-form-builder/ajax/_src/bfb-ajax.js

1,139 lines 35.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // ---------------------------------------------------------------------------------------------------------------------
2 // == 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.
3 // ---------------------------------------------------------------------------------------------------------------------
4 (function (w, d, $) {
5 'use strict';
6
7 var AjaxCfg = w.WPBC_BFB_Ajax || {};
8 if ( ! AjaxCfg.url ) {
9 // Not on builder page or config not injected.
10 return;
11 }
12
13 if ( ! $ || ! $.ajax ) {
14 // In WP admin jQuery should exist; if not, stop to avoid silent corruption.
15 wpbc_admin_show_message( 'WPBC BFB: jQuery is not available.', 'error', 10000 );
16 console.error( 'WPBC BFB: jQuery is not available.' );
17 return;
18 }
19
20 function get_save_source( cfg, btn ) {
21
22 // priority: button attr -> global cfg -> default
23 var v = '';
24 try {
25 if ( btn && btn.getAttribute ) {
26 v = btn.getAttribute( 'data-wpbc-bfb-save-source' ) || '';
27 }
28 } catch ( e ) {}
29
30 if ( ! v && cfg && cfg.save_source ) {
31 v = cfg.save_source;
32 }
33
34 v = String( v || 'auto' ).toLowerCase();
35 if ( [ 'builder', 'advanced', 'auto' ].indexOf( v ) === -1 ) {
36 v = 'builder';
37 }
38 return v;
39 }
40
41 function read_advanced_mode_payload() {
42
43 // best: API (syncs CodeMirror -> textarea)
44 if ( w.wpbc_bfb_advanced_editor_api && typeof w.wpbc_bfb_advanced_editor_api.get_values === 'function' ) {
45 try {
46 return w.wpbc_bfb_advanced_editor_api.get_values();
47 } catch ( e ) {}
48 }
49
50 // fallback: read textareas directly (may be stale if CM not saved)
51 var ta_form = d.getElementById( 'wpbc_bfb__advanced_form_editor' );
52 var ta_content = d.getElementById( 'wpbc_bfb__content_form_editor' );
53
54 return {
55 advanced_form: ta_form ? String( ta_form.value || '' ) : '',
56 content_form : ta_content ? String( ta_content.value || '' ) : '',
57 is_dirty : false
58 };
59 }
60
61 function has_text( v ) {
62 return !! ( v && String( v ).trim() );
63 }
64
65 /**
66 * Serialize values so payload matches previous XMLHttpRequest behavior:
67 * - null/undefined => ''
68 * - objects/arrays => JSON.stringify(...)
69 * - everything else => String(...)
70 *
71 * @param {*} value
72 * @return {string}
73 */
74 function wpbc_bfb__serialize_post_value( value ) {
75
76 if ( value === null || typeof value === 'undefined' ) {
77 return '';
78 }
79
80 if ( typeof value === 'object' ) {
81 try {
82 return JSON.stringify( value );
83 } catch ( e ) {
84 return '';
85 }
86 }
87
88 return String( value );
89 }
90
91 /**
92 * Normalize payload to scalar strings so jQuery does not produce "[object Object]".
93 *
94 * @param {Object} raw_data
95 * @return {Object}
96 */
97 function wpbc_bfb__normalize_post_data( raw_data ) {
98
99 var out = {};
100 raw_data = raw_data || {};
101
102 for ( var k in raw_data ) {
103 if ( ! Object.prototype.hasOwnProperty.call( raw_data, k ) ) {
104 continue;
105 }
106 out[ k ] = wpbc_bfb__serialize_post_value( raw_data[ k ] );
107 }
108
109 return out;
110 }
111
112 /**
113 * POST helper (jQuery only) returning jqXHR promise.
114 * IMPORTANT: dataType:'text' so callers keep manual JSON.parse exactly as before.
115 *
116 * @param {string} url
117 * @param {Object} payload
118 * @return {jqXHR}
119 */
120 function wpbc_bfb__ajax_post( url, payload ) {
121
122 return $.ajax( {
123 url : url,
124 type : 'POST',
125 data : wpbc_bfb__normalize_post_data( payload ),
126 dataType : 'text',
127 contentType : 'application/x-www-form-urlencoded; charset=UTF-8'
128 } );
129 }
130
131 /**
132 * Safe JSON parse helper.
133 *
134 * @param {string} text
135 * @return {Object|null}
136 */
137 function wpbc_bfb__safe_json_parse( text ) {
138 try {
139 return JSON.parse( text );
140 } catch ( e ) {
141 return null;
142 }
143 }
144
145 /**
146 * Parse combined length string like "100%", "320px", "12.5rem".
147 *
148 * @param {string} value
149 * @return {{num:string, unit:string}}
150 */
151 function parse_length_value( value ) {
152 var raw = String( value == null ? '' : value ).trim();
153 var m = raw.match( /^\s*(-?\d+(?:\.\d+)?)\s*([a-z%]*)\s*$/i );
154 if ( ! m ) {
155 return { num: raw, unit: '' };
156 }
157 return { num: ( m[1] || '' ), unit: ( m[2] || '' ) };
158 }
159
160 /**
161 * SAVE: send current Builder structure (+ exported shortcodes) to PHP.
162 *
163 * Uses:
164 * - WPBC_BFB_Ajax.url / nonce_save / form_name / engine / engine_version
165 * - Optional WPBC_BFB_Exporter.export_all()
166 * - Busy helpers wpbc_bfb__button_busy_start / _end if available.
167 *
168 * IMPORTANT:
169 * - Local (form) settings are collected ONLY here (Save form),
170 * via event "wpbc:bfb:form_settings:collect".
171 */
172 function wpbc_bfb__ajax_save_current_form( btn, done_cb ) {
173
174 var cfg = w.WPBC_BFB_Ajax || {};
175 var builder = w.wpbc_bfb || null;
176
177 var $btn = btn ? $( btn ) : null;
178
179 // --- Busy START ----------------------------------------------------------------------------------------------
180 if ( $btn && $btn.length ) {
181 // Will read data-wpbc-u-busy-text="Saving..." from the <a> and add spinner.
182 if ( typeof w.wpbc_bfb__button_busy_start === 'function' ) { // FIX: guard
183 w.wpbc_bfb__button_busy_start( $btn );
184 } else {
185 $btn.prop( 'disabled', true );
186 }
187 } else if ( btn ) {
188 btn.disabled = true;
189 }
190
191 // --- Gather structure ----------------------------------------------------------------------------------------
192 var structure = ( builder && typeof builder.get_structure === 'function' ) ? builder.get_structure() : [];
193
194 // --- Gather current form settings (event-based; modules can contribute) -------------------------------------
195 // ONLY supported settings format:
196 // {
197 // options : { key: value, ... },
198 // css_vars : [],
199 // bfb_options : { advanced_mode_source: 'builder'|'advanced'|'auto' }
200 // }
201 var form_settings = {
202 options : {},
203 css_vars : [],
204 bfb_options : { advanced_mode_source: 'builder' }
205 };
206
207 // Let Settings Options (and any other module) contribute local form settings.
208 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form_settings:collect', {
209 settings : form_settings,
210 form_name: cfg.form_name || 'standard'
211 } );
212
213 // Normalize css_vars to array (schema enforcement).
214 if ( form_settings && form_settings.css_vars && ! Array.isArray( form_settings.css_vars ) ) {
215 var out = [];
216 try {
217 for ( var k in form_settings.css_vars ) {
218 if ( Object.prototype.hasOwnProperty.call( form_settings.css_vars, k ) ) {
219 out.push( { name: String( k ), value: String( form_settings.css_vars[ k ] ) } );
220 }
221 }
222 } catch ( _e0 ) {}
223 form_settings.css_vars = out;
224 }
225 if ( ! form_settings.bfb_options || typeof form_settings.bfb_options !== 'object' ) {
226 form_settings.bfb_options = { advanced_mode_source: 'builder' };
227 }
228 if ( ! form_settings.bfb_options.advanced_mode_source ) {
229 form_settings.bfb_options.advanced_mode_source = 'builder';
230 }
231
232 var payload = {
233 action : 'WPBC_AJX_BFB_SAVE_FORM_CONFIG',
234 nonce : cfg.nonce_save || '',
235 form_name : cfg.form_name || 'standard',
236 engine : cfg.engine || 'bfb',
237 engine_version: cfg.engine_version || '1.0',
238 structure : JSON.stringify( structure ),
239 settings : JSON.stringify( form_settings )
240 };
241
242 // -----------------------------------------------------------------------------
243 // Choose where advanced_form + content_form are taken from.
244 // -----------------------------------------------------------------------------
245 var save_source = get_save_source( cfg, btn );
246
247 // 1) Try Advanced Mode text (if selected / auto+dirty).
248 var adv = null;
249
250 if ( save_source === 'advanced' || save_source === 'auto' ) {
251 adv = read_advanced_mode_payload();
252
253 var can_use_advanced =
254 ( save_source === 'advanced' ) ||
255 ( save_source === 'auto' && adv && adv.is_dirty );
256
257 if ( can_use_advanced ) {
258
259 // If user forced "advanced" but both are empty -> fallback to exporter.
260 if ( ! has_text( adv.advanced_form ) && ! has_text( adv.content_form ) ) {
261 wpbc_admin_show_message( 'Advanced Mode is selected, but editors are empty. Using Builder export.', 'warning', 6000 );
262 } else {
263 if ( has_text( adv.advanced_form ) ) {
264 payload.advanced_form = adv.advanced_form;
265 }
266 if ( has_text( adv.content_form ) ) {
267 payload.content_form = adv.content_form;
268 }
269 form_settings.bfb_options.advanced_mode_source = 'advanced';
270 payload.settings = JSON.stringify( form_settings ); // keep payload in sync.
271 }
272 }
273 }
274
275 // 2) If not taken from Advanced Mode -> export from Builder structure (current behavior).
276 if ( ! payload.advanced_form || ! payload.content_form ) {
277
278 if ( w.WPBC_BFB_Exporter && typeof w.WPBC_BFB_Exporter.export_all === 'function' ) {
279 try {
280
281 // Prefer Option A pack: settings.options.*
282 var opt_pack = form_settings.options;
283 var width_combined = opt_pack.booking_form_layout_width || '';
284 var parsed_width = parse_length_value( width_combined );
285
286 var export_options = {
287 gapPercent : 3,
288 form_slug : payload.form_name,
289 form_width_value: parsed_width.num,
290 form_width_unit : parsed_width.unit
291 };
292
293 var export_result = w.WPBC_BFB_Exporter.export_all( structure || [], export_options );
294
295 if ( export_result ) {
296 if ( ! payload.advanced_form && export_result.advanced_form ) {
297 payload.advanced_form = export_result.advanced_form;
298 }
299 if ( ! payload.content_form && export_result.fields_data ) {
300 payload.content_form = export_result.fields_data;
301 }
302 }
303
304 form_settings.bfb_options.advanced_mode_source = 'builder';
305 payload.settings = JSON.stringify( form_settings ); // keep payload in sync.
306
307 } catch ( e ) {
308 wpbc_admin_show_message( 'WPBC BFB: export_all error', 'error', 10000 );
309 console.error( 'WPBC BFB: export_all error', e );
310 }
311 }
312 }
313
314 // Update payload before send via AJAX, if needed.
315 var hook_detail = { payload: payload };
316 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:before_save_payload', hook_detail );
317 payload = hook_detail.payload;
318
319 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
320
321 ajax_request
322 .done(
323 function ( response_text, _text_status, jqxhr ) {
324
325 // Keep old behavior: only treat exact 200 as success.
326 if ( ! jqxhr || jqxhr.status !== 200 ) {
327 if ( typeof done_cb === 'function' ) {
328 try { done_cb( false, null ); } catch ( _e1 ) {}
329 }
330 wpbc_admin_show_message( 'WPBC BFB: save HTTP error', 'error', 10000 );
331 console.error( 'WPBC BFB: save HTTP error', jqxhr ? jqxhr.status : 0 );
332 return;
333 }
334
335 var resp = wpbc_bfb__safe_json_parse( response_text );
336 if ( ! resp ) {
337 wpbc_admin_show_message( 'WPBC BFB: save JSON parse error', 'error', 10000 );
338 console.error( 'WPBC BFB: save JSON parse error', response_text );
339 return;
340 }
341
342 if ( ! resp || ! resp.success ) {
343 const error_message = ( resp.data && resp.data.message ) ? resp.data.message : '';
344 wpbc_admin_show_message( 'WPBC BFB: save failed.' + ' | ' + error_message, 'error', 10000 );
345 console.error( 'WPBC BFB: save failed', resp );
346 return;
347 }
348
349 if ( typeof done_cb === 'function' ) {
350 try { done_cb( true, resp ); } catch ( _e2 ) {}
351 }
352
353 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:ajax_saved', {
354 loaded_data: resp.data,
355 form_name : cfg.form_name || 'standard'
356 } );
357 if (
358 resp.data
359 && resp.data.setup_step_saved
360 && typeof w.wpbc_setup_wizard_set_current_step_saved === 'function'
361 ) {
362 try {
363 w.wpbc_setup_wizard_set_current_step_saved();
364 } catch ( _e_setup_set ) {}
365 } else if ( typeof w.wpbc_setup_wizard_mark_current_step_saved === 'function' ) {
366 try {
367 w.wpbc_setup_wizard_mark_current_step_saved();
368 } catch ( _e_setup ) {}
369 }
370
371 // Optional: visual feedback.
372 wpbc_admin_show_message( 'Form saved', 'success', 1000, false );
373 }
374 )
375 .fail( function ( jqxhr ) {
376
377 // Old behavior: status != 200 triggers done_cb(false, null).
378 if ( typeof done_cb === 'function' ) {
379 try { done_cb( false, null ); } catch ( _e3 ) {}
380 }
381
382 wpbc_admin_show_message( 'WPBC BFB: save HTTP error', 'error', 10000 );
383 console.error( 'WPBC BFB: save HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
384 } )
385 .always( function () {
386
387 // --- Busy END (always) ----------------------------------------------------------------------------------
388 if ( $btn && $btn.length && typeof w.wpbc_bfb__button_busy_end === 'function' ) {
389 w.wpbc_bfb__button_busy_end( $btn );
390 } else if ( $btn && $btn.length ) {
391 $btn.prop( 'disabled', false ).removeClass( 'wpbc-is-busy' );
392 } else if ( btn ) {
393 btn.disabled = false;
394 }
395 } );
396 }
397
398 function apply_advanced_mode_texts( advanced_form, content_form, advanced_mode_source ) {
399
400 var af = ( advanced_form == null ) ? '' : String( advanced_form );
401 var cf = ( content_form == null ) ? '' : String( content_form );
402
403 // Always update underlying <textarea> so it works even if CodeMirror isn't inited yet.
404 var ta_form = d.getElementById( 'wpbc_bfb__advanced_form_editor' );
405 var ta_content = d.getElementById( 'wpbc_bfb__content_form_editor' );
406
407 if ( ta_form ) {
408 ta_form.value = af;
409 }
410 if ( ta_content ) {
411 ta_content.value = cf;
412 }
413
414 // Notify Advanced Mode module (if loaded) to sync CodeMirror + flags.
415 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:advanced_text:apply', {
416 advanced_form : af,
417 content_form : cf,
418 advanced_mode_source: advanced_mode_source
419 } );
420 }
421
422 /**
423 * LOAD: fetch FormConfig from PHP and hand structure to Builder.
424 *
425 * Also uses busy helpers if available.
426 */
427 function wpbc_bfb__ajax_load_current_form( btn, done_cb ) {
428
429 var cfg = w.WPBC_BFB_Ajax || {};
430 var builder = w.wpbc_bfb || null;
431
432 var $btn = btn ? $( btn ) : null;
433
434 // --- Busy START ----------------------------------------------------------------------------------------------
435 if ( $btn && $btn.length ) {
436 if ( typeof w.wpbc_bfb__button_busy_start === 'function' ) { // FIX: guard
437 w.wpbc_bfb__button_busy_start( $btn );
438 } else {
439 $btn.prop( 'disabled', true );
440 }
441 } else if ( btn ) {
442 btn.disabled = true;
443 }
444
445 var payload = {
446 action : 'WPBC_AJX_BFB_LOAD_FORM_CONFIG',
447 nonce : cfg.nonce_load || '',
448 form_name: cfg.form_name || 'standard'
449 };
450
451 wpbc_admin_show_message_processing( '' );
452 // wpbc_admin_show_message( 'Processing', 'info', 1000, false ); // Optional: visual feedback.
453
454 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
455
456 ajax_request
457 .done( function ( response_text, _text_status, jqxhr ) {
458
459 if ( ! jqxhr || jqxhr.status !== 200 ) {
460
461 if ( typeof done_cb === 'function' ) {
462 try { done_cb( false, null ); } catch ( _e0 ) {}
463 }
464
465 wpbc_admin_show_message( 'WPBC BFB: load HTTP error', 'error', 10000 );
466 console.error( 'WPBC BFB: load HTTP error', jqxhr ? jqxhr.status : 0 );
467 return;
468 }
469
470 var resp = wpbc_bfb__safe_json_parse( response_text );
471 if ( ! resp ) {
472 wpbc_admin_show_message( 'WPBC BFB: load JSON parse error', 'error', 10000 );
473 console.error( 'WPBC BFB: load JSON parse error', response_text );
474 return;
475 }
476
477 if ( ! resp || ! resp.success || ! resp.data ) {
478 wpbc_admin_show_message( 'WPBC BFB: load failed', 'error', 10000 );
479 console.error( 'WPBC BFB: load failed', resp );
480 return;
481 }
482
483 var data = resp.data;
484 var structure = data.structure || [];
485
486 // Apply Advanced Mode saved texts (if provided by PHP).
487 if ( data && ( typeof data.advanced_form !== 'undefined' || typeof data.content_form !== 'undefined' ) ) {
488 var ams = '';
489 try {
490 var s1 = ( typeof data.settings === 'string' ) ? JSON.parse( data.settings ) : data.settings;
491 ams = ( s1 && s1.bfb_options && s1.bfb_options.advanced_mode_source ) ? s1.bfb_options.advanced_mode_source : '';
492 } catch ( _e1 ) {}
493
494 apply_advanced_mode_texts(
495 data.advanced_form || '',
496 data.content_form || '',
497 ams
498 );
499 }
500
501 // Apply settings to UI (local form settings) if provided.
502 if ( data.settings ) {
503 var parsed_settings = null;
504 try {
505 parsed_settings = ( typeof data.settings === 'string' ) ? JSON.parse( data.settings ) : data.settings;
506 } catch ( _e2 ) {
507 parsed_settings = null;
508 }
509 if ( parsed_settings ) {
510 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form_settings:apply', {
511 settings : parsed_settings,
512 form_name: cfg.form_name || 'standard'
513 } );
514 }
515 }
516
517 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:ajax_loaded', {
518 loaded_data: data,
519 form_name : cfg.form_name || 'standard'
520 } );
521
522 if ( typeof done_cb === 'function' ) {
523 try { done_cb( true, data ); } catch ( _e3 ) {}
524 }
525
526 // Prefer your existing callback if it already knows how to init Builder.
527 if ( typeof w.wpbc_bfb__on_structure_loaded === 'function' ) {
528 w.wpbc_bfb__on_structure_loaded( structure );
529 wpbc_admin_show_message( 'Done', 'info', 1000, false );
530 } else if ( builder && typeof builder.load_structure === 'function' ) {
531 builder.load_structure( structure );
532 wpbc_admin_show_message( 'Done', 'info', 1000, false );
533 } else {
534 console.warn( 'WPBC BFB: no loader for structure', structure );
535 }
536 } )
537 .fail( function ( jqxhr ) {
538
539 if ( typeof done_cb === 'function' ) {
540 try { done_cb( false, null ); } catch ( _e4 ) {}
541 }
542
543 wpbc_admin_show_message( 'WPBC BFB: load HTTP error', 'error', 10000 );
544 console.error( 'WPBC BFB: load HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
545 } )
546 .always( function () {
547
548 // --- Busy END (always) ----------------------------------------------------------------------------------
549 if ( $btn && $btn.length && typeof w.wpbc_bfb__button_busy_end === 'function' ) {
550 w.wpbc_bfb__button_busy_end( $btn );
551 } else if ( $btn && $btn.length ) {
552 $btn.prop( 'disabled', false ).removeClass( 'wpbc-is-busy' );
553 } else if ( btn ) {
554 btn.disabled = false;
555 }
556 } );
557 }
558
559 function wpbc_bfb__ajax_create_form( btn, create_payload, template_form_key, done_cb ) {
560
561 var cfg = w.WPBC_BFB_Ajax || {};
562
563 if ( ! cfg.url || ! cfg.nonce_create ) {
564 wpbc_admin_show_message( 'WPBC BFB: create config is missing (url/nonce).', 'error', 10000 );
565 if ( typeof done_cb === 'function' ) {
566 done_cb( false, null );
567 }
568 return;
569 }
570
571 template_form_key = String( template_form_key || '' ).trim();
572 if ( template_form_key === '__blank__' ) {
573 template_form_key = '';
574 }
575
576 var payload = {
577 action : 'WPBC_AJX_BFB_CREATE_FORM_CONFIG',
578 nonce : cfg.nonce_create,
579 form_name : String( create_payload.form_slug || '' ),
580 template_form_name: template_form_key || '',
581 title : String( create_payload.form_title || '' ),
582 description : String( create_payload.form_description || '' ),
583 image_url : String( create_payload.form_image_url || '' )
584 };
585
586 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
587
588 ajax_request
589 .done( function ( response_text, _text_status, jqxhr ) {
590
591 if ( ! jqxhr || jqxhr.status !== 200 ) {
592 wpbc_admin_show_message( 'WPBC BFB: create HTTP error', 'error', 10000 );
593 if ( typeof done_cb === 'function' ) {
594 done_cb( false, null );
595 }
596 return;
597 }
598
599 var resp = wpbc_bfb__safe_json_parse( response_text );
600 if ( ! resp ) {
601 wpbc_admin_show_message( 'WPBC BFB: create JSON parse error', 'error', 10000 );
602 if ( typeof done_cb === 'function' ) {
603 done_cb( false, null );
604 }
605 return;
606 }
607
608 if ( ! resp || ! resp.success || ! resp.data ) {
609 var msg = ( resp && resp.data && resp.data.message ) ? resp.data.message : 'WPBC BFB: create failed';
610 wpbc_admin_show_message( msg, 'error', 10000 );
611 if ( typeof done_cb === 'function' ) {
612 done_cb( false, resp );
613 }
614 return;
615 }
616
617 // Switch current form to the newly created key.
618 cfg.form_name = resp.data.form_name || create_payload.form_slug;
619
620 if ( typeof done_cb === 'function' ) {
621 done_cb( true, resp );
622 }
623 } )
624 .fail( function ( jqxhr ) {
625 wpbc_admin_show_message( 'WPBC BFB: create HTTP error', 'error', 10000 );
626 if ( typeof done_cb === 'function' ) {
627 done_cb( false, null );
628 }
629 console.error( 'WPBC BFB: create HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
630 } );
631 }
632
633 // Load ALL Forms.
634 function wpbc_bfb__ajax_list_user_forms( btn, args, done_cb ) {
635
636 var cfg = w.WPBC_BFB_Ajax || {};
637
638 if ( ! cfg.url || ! cfg.nonce_list ) {
639 wpbc_admin_show_message( 'WPBC BFB: list config is missing (url/nonce_list).', 'error', 10000 );
640 if ( typeof done_cb === 'function' ) {
641 done_cb( false, null );
642 }
643 return;
644 }
645
646 var page = ( args && args.page ) ? parseInt( args.page, 10 ) : 1;
647 var limit = ( args && ( args.limit || args.per_page ) ) ? parseInt( ( args.limit || args.per_page ), 10 ) : 20;
648
649 if ( ! page || page < 1 ) {
650 page = 1;
651 }
652 if ( ! limit || limit < 1 ) {
653 limit = 20;
654 }
655
656 var payload = {
657 action : 'WPBC_AJX_BFB_LIST_FORMS',
658 nonce : cfg.nonce_list,
659 include_global: ( args && args.include_global ) ? 1 : 0,
660 status : ( args && args.status ) ? String( args.status ) : 'published',
661 search : ( args && args.search ) ? String( args.search ) : '',
662 page : page,
663 limit : limit
664 };
665
666 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
667
668 ajax_request
669 .done( function ( response_text, _text_status, jqxhr ) {
670
671 if ( ! jqxhr || jqxhr.status !== 200 ) {
672 wpbc_admin_show_message( 'WPBC BFB: list HTTP error', 'error', 10000 );
673 if ( typeof done_cb === 'function' ) {
674 done_cb( false, null );
675 }
676 return;
677 }
678
679 var resp = wpbc_bfb__safe_json_parse( response_text );
680 if ( ! resp ) {
681 wpbc_admin_show_message( 'WPBC BFB: list JSON parse error', 'error', 10000 );
682 if ( typeof done_cb === 'function' ) {
683 done_cb( false, null );
684 }
685 return;
686 }
687
688 if ( ! resp || ! resp.success || ! resp.data ) {
689 wpbc_admin_show_message( 'WPBC BFB: list failed', 'error', 10000 );
690 if ( typeof done_cb === 'function' ) {
691 done_cb( false, resp );
692 }
693 return;
694 }
695
696 if ( typeof done_cb === 'function' ) {
697 done_cb( true, resp.data );
698 }
699 } )
700 .fail( function ( jqxhr ) {
701 wpbc_admin_show_message( 'WPBC BFB: list HTTP error', 'error', 10000 );
702 if ( typeof done_cb === 'function' ) {
703 done_cb( false, null );
704 }
705 console.error( 'WPBC BFB: list HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
706 } );
707 }
708
709 function wpbc_bfb__ajax_load_form_by_slug( form_slug, btn, done_cb ) {
710
711 var cfg = w.WPBC_BFB_Ajax || {};
712 var builder = w.wpbc_bfb || null;
713
714 form_slug = String( form_slug || '' ).trim();
715 if ( ! form_slug ) {
716 if ( typeof done_cb === 'function' ) {
717 done_cb( false, null );
718 }
719 return;
720 }
721
722 var $btn = btn ? $( btn ) : null;
723
724 // Busy START
725 if ( $btn && $btn.length ) {
726 if ( typeof w.wpbc_bfb__button_busy_start === 'function' ) {
727 w.wpbc_bfb__button_busy_start( $btn );
728 } else {
729 $btn.prop( 'disabled', true );
730 }
731 } else if ( btn ) {
732 btn.disabled = true;
733 }
734
735 var payload = {
736 action : 'WPBC_AJX_BFB_LOAD_FORM_CONFIG',
737 nonce : cfg.nonce_load || '',
738 form_name: form_slug
739 };
740
741 wpbc_admin_show_message_processing( '' );
742
743 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
744
745 ajax_request
746 .done( function ( response_text, _text_status, jqxhr ) {
747
748 if ( ! jqxhr || jqxhr.status !== 200 ) {
749 wpbc_admin_show_message( 'WPBC BFB: load HTTP error', 'error', 10000 );
750 if ( typeof done_cb === 'function' ) {
751 done_cb( false, null );
752 }
753 return;
754 }
755
756 var resp = wpbc_bfb__safe_json_parse( response_text );
757 if ( ! resp ) {
758 wpbc_admin_show_message( 'WPBC BFB: load JSON parse error', 'error', 10000 );
759 if ( typeof done_cb === 'function' ) {
760 done_cb( false, null );
761 }
762 return;
763 }
764
765 if ( ! resp || ! resp.success || ! resp.data ) {
766
767 if ( resp && resp.data && resp.data.message ) {
768 wpbc_admin_show_message( 'WPBC BFB: ' + resp.data.message, 'error', 10000 );
769 } else {
770 wpbc_admin_show_message( 'WPBC BFB: load failed', 'error', 10000 );
771 }
772
773 if ( typeof done_cb === 'function' ) {
774 done_cb( false, resp );
775 }
776 return;
777 }
778
779 var data = resp.data;
780 var structure = data.structure || [];
781
782 // IMPORTANT: switch "current form" after successful load
783 cfg.form_name = form_slug;
784
785 // Apply Advanced Mode texts if present.
786 if ( data && ( typeof data.advanced_form !== 'undefined' || typeof data.content_form !== 'undefined' ) ) {
787
788 var ams2 = '';
789 try {
790 var s2 = ( typeof data.settings === 'string' ) ? JSON.parse( data.settings ) : data.settings;
791 ams2 = ( s2 && s2.bfb_options && s2.bfb_options.advanced_mode_source ) ? s2.bfb_options.advanced_mode_source : '';
792 } catch ( _e2 ) {}
793
794 apply_advanced_mode_texts(
795 data.advanced_form || '',
796 data.content_form || '',
797 ams2
798 );
799 }
800
801 // Apply settings if present.
802 if ( data.settings ) {
803 var parsed_settings = null;
804 try {
805 parsed_settings = ( typeof data.settings === 'string' ) ? JSON.parse( data.settings ) : data.settings;
806 } catch ( _e3 ) {
807 parsed_settings = null;
808 }
809 if ( parsed_settings ) {
810 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form_settings:apply', {
811 settings : parsed_settings,
812 form_name: cfg.form_name || 'standard'
813 } );
814 }
815 }
816
817 wpbc_bfb__dispatch_event_safe( 'wpbc:bfb:form:ajax_loaded', {
818 loaded_data: data,
819 form_name : cfg.form_name || 'standard'
820 } );
821
822 if ( typeof done_cb === 'function' ) {
823 try { done_cb( true, data ); } catch ( _e4 ) {}
824 }
825
826 if ( typeof w.wpbc_bfb__on_structure_loaded === 'function' ) {
827 w.wpbc_bfb__on_structure_loaded( structure );
828 wpbc_admin_show_message( 'Done', 'info', 1000, false );
829 } else if ( builder && typeof builder.load_structure === 'function' ) {
830 builder.load_structure( structure );
831 wpbc_admin_show_message( 'Done', 'info', 1000, false );
832 } else {
833 console.warn( 'WPBC BFB: no loader for structure', structure );
834 }
835 } )
836 .fail( function ( jqxhr ) {
837 wpbc_admin_show_message( 'WPBC BFB: load HTTP error', 'error', 10000 );
838 if ( typeof done_cb === 'function' ) {
839 done_cb( false, null );
840 }
841 console.error( 'WPBC BFB: load HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
842 } )
843 .always( function () {
844
845 // Busy END
846 if ( $btn && $btn.length && typeof w.wpbc_bfb__button_busy_end === 'function' ) {
847 w.wpbc_bfb__button_busy_end( $btn );
848 } else if ( $btn && $btn.length ) {
849 $btn.prop( 'disabled', false ).removeClass( 'wpbc-is-busy' );
850 } else if ( btn ) {
851 btn.disabled = false;
852 }
853 } );
854 }
855
856 function wpbc_bfb__ajax_delete_template_by_slug( form_slug, done_cb ) {
857
858 var cfg = w.WPBC_BFB_Ajax || {};
859 var delete_nonce = cfg.nonce_delete || cfg.nonce_list || '';
860
861 form_slug = String( form_slug || '' ).trim();
862
863 if ( ! form_slug ) {
864 if ( typeof done_cb === 'function' ) {
865 done_cb( false, { data: { message: 'Template key is required.' } } );
866 }
867 return;
868 }
869
870 if ( ! cfg.url || ! delete_nonce ) {
871 console.error( 'WPBC BFB: delete template config is missing (url/nonce).' );
872 if ( typeof done_cb === 'function' ) {
873 done_cb( false, { data: { message: 'WPBC BFB: delete template config is missing (url/nonce).' } } );
874 }
875 return;
876 }
877
878 var payload = {
879 action : 'WPBC_AJX_BFB_DELETE_TEMPLATE_CONFIG',
880 nonce : delete_nonce,
881 form_name: form_slug
882 };
883
884 var ajax_request = wpbc_bfb__ajax_post( cfg.url, payload );
885
886 ajax_request
887 .done( function ( response_text, _text_status, jqxhr ) {
888
889 if ( ! jqxhr || jqxhr.status !== 200 ) {
890 if ( typeof done_cb === 'function' ) {
891 done_cb( false, null );
892 }
893 return;
894 }
895
896 var resp = wpbc_bfb__safe_json_parse( response_text );
897 if ( ! resp ) {
898 if ( typeof done_cb === 'function' ) {
899 done_cb( false, null );
900 }
901 return;
902 }
903
904 if ( ! resp.success ) {
905 if ( typeof done_cb === 'function' ) {
906 done_cb( false, resp );
907 }
908 return;
909 }
910
911 if ( typeof done_cb === 'function' ) {
912 done_cb( true, resp );
913 }
914 } )
915 .fail( function ( jqxhr ) {
916 if ( typeof done_cb === 'function' ) {
917 done_cb( false, null );
918 }
919 console.error( 'WPBC BFB: delete template HTTP error', jqxhr && jqxhr.status, jqxhr && jqxhr.statusText );
920 } );
921 }
922
923
924 // Expose globals for buttons (onclick attributes).
925 w.wpbc_bfb__ajax_delete_template_by_slug = wpbc_bfb__ajax_delete_template_by_slug;
926 w.wpbc_bfb__ajax_save_current_form = wpbc_bfb__ajax_save_current_form;
927 w.wpbc_bfb__ajax_load_current_form = wpbc_bfb__ajax_load_current_form;
928 w.wpbc_bfb__ajax_create_form = wpbc_bfb__ajax_create_form;
929 w.wpbc_bfb__ajax_list_user_forms = wpbc_bfb__ajax_list_user_forms;
930 w.wpbc_bfb__ajax_load_form_by_slug = wpbc_bfb__ajax_load_form_by_slug;
931
932 })( window, document, window.jQuery );
933
934
935 // -- Ajax Helpers: ----------------------------------------------------------------------------------------------------
936 /**
937 * Common callback used by loaders that return structure JSON.
938 *
939 * @param val
940 */
941 function wpbc_bfb__on_structure_loaded( val ) {
942 try {
943 if ( typeof val === 'string' ) {
944 val = JSON.parse( val );
945 }
946 var builder = window.wpbc_bfb || null; // FIX: use window.*
947 if ( builder && typeof builder.load_saved_structure === 'function' ) {
948 builder.load_saved_structure( val || [] );
949 }
950 } catch ( e ) {
951 wpbc_admin_show_message( 'wpbc_bfb__on_structure_loaded error', 'error', 10000 );
952 console.error( 'wpbc_bfb__on_structure_loaded error', e );
953 }
954 }
955
956 function wpbc_bfb__get_ajax_url() {
957 if ( typeof ajaxurl !== 'undefined' && ajaxurl ) {
958 return ajaxurl;
959 }
960
961 var AjaxCfg = window.WPBC_BFB_Ajax || {}; // FIX: guard via window.*
962 if ( AjaxCfg.url ) {
963 return AjaxCfg.url;
964 }
965
966 wpbc_admin_show_message( 'WPBC BFB: ajax URL is missing.', 'error', 10000 );
967 console.error( 'WPBC BFB: ajax URL is missing.' );
968 return '';
969 }
970
971
972 // -- Shared helpers: button busy state --------------------------------------------------------------------------------
973 function wpbc_bfb__button_busy_start( $btn ) {
974
975 if ( ! $btn || ! $btn.length ) return;
976
977 var original_html = $btn.html();
978 var busy_text = $btn.data( 'wpbc-u-busy-text' ) || '';
979 var spinner_html = '<span class="wpbc_icn_rotate_right wpbc_spin wpbc_ajax_icon wpbc_processing wpbc_icn_autorenew" aria-hidden="true"></span>';
980
981 $btn
982 .data( 'wpbc-original-html', original_html )
983 .prop( 'disabled', true )
984 .addClass( 'wpbc-is-busy' );
985
986 if ( busy_text ) {
987 $btn.html( busy_text + ' ' + spinner_html );
988 } else {
989 $btn.append( spinner_html );
990 }
991 }
992
993 function wpbc_bfb__button_busy_end( $btn ) {
994 if ( ! $btn || ! $btn.length ) return;
995
996 var original = $btn.data( 'wpbc-original-html' );
997 if ( typeof original === 'string' ) {
998 $btn.html( original );
999 }
1000 $btn
1001 .prop( 'disabled', false )
1002 .removeClass( 'wpbc-is-busy' )
1003 .removeData( 'wpbc-original-html' );
1004 }
1005
1006
1007 // -- Import Helpers: --------------------------------------------------------------------------------------------------
1008 /**
1009 * Import from Simple Form — with busy state
1010 *
1011 * @param btn
1012 */
1013 function wpbc_bfb__import_from_simple_form( btn ) {
1014 try {
1015 var $btn = jQuery( btn );
1016 var nonce = $btn.data( 'wpbc-bfb-import-nonce' );
1017 var action = $btn.data( 'wpbc-bfb-import-action' ) || 'wpbc_bfb_import_simple_form';
1018
1019 if ( ! nonce ) {
1020 wpbc_admin_show_message( 'WPBC BFB: missing import nonce.', 'error', 10000 );
1021 console.error( 'WPBC BFB: missing import nonce.' );
1022 return;
1023 }
1024
1025 var ajax_url = wpbc_bfb__get_ajax_url();
1026 if ( ! ajax_url ) {
1027 return;
1028 }
1029
1030 wpbc_bfb__button_busy_start( $btn );
1031
1032 wpbc_admin_show_message_processing( '' );
1033
1034 jQuery.post( ajax_url, {
1035 action: action,
1036 nonce : nonce
1037 } )
1038 .done( function ( resp ) {
1039 if ( resp && resp.success && resp.data && resp.data.structure ) {
1040 var builder = window.wpbc_bfb || null; // FIX: use window.*
1041 if ( builder && typeof builder.load_saved_structure === 'function' ) {
1042 builder.load_saved_structure( resp.data.structure || [] );
1043 wpbc_admin_show_message( 'Done', 'info', 1000, false );
1044 }
1045 } else {
1046 wpbc_admin_show_message( 'WPBC BFB: import error', 'error', 10000 );
1047 console.error( 'WPBC BFB: import error', resp );
1048 }
1049 } )
1050 .fail( function ( xhr ) {
1051 wpbc_admin_show_message( 'WPBC BFB: AJAX error', 'error', 10000 );
1052 console.error( 'WPBC BFB: AJAX error', xhr.status, xhr.statusText );
1053 } )
1054 .always( function () {
1055 wpbc_bfb__button_busy_end( $btn );
1056 } );
1057
1058 } catch ( e ) {
1059 wpbc_admin_show_message( 'WPBC BFB: import exception', 'error', 10000 );
1060 console.error( 'WPBC BFB: import exception', e );
1061 }
1062 }
1063
1064 /**
1065 * Import legacy booking forms into BFB storage.
1066 *
1067 * Supported modes:
1068 * - current_context
1069 * - all_global
1070 * - all_users
1071 *
1072 * @param btn
1073 */
1074 function wpbc_bfb__import_legacy_forms( btn ) {
1075 try {
1076 var $btn = jQuery( btn );
1077 var nonce = $btn.data( 'wpbc-bfb-import-nonce' );
1078 var action = $btn.data( 'wpbc-bfb-import-action' ) || 'WPBC_AJX_BFB_IMPORT_LEGACY_FORMS';
1079 var mode = $btn.data( 'wpbc-bfb-import-mode' ) || 'current_context';
1080
1081 var skip_if_exists = $btn.data( 'wpbc-bfb-skip-if-exists' ) || 'skip';
1082 var set_bfb_form_not_defined = $btn.data( 'wpbc-bfb-set-form-not-defined' ) || 'not_defined';
1083
1084 if ( ! nonce ) {
1085 wpbc_admin_show_message( 'WPBC BFB: missing legacy import nonce.', 'error', 10000 );
1086 console.error( 'WPBC BFB: missing legacy import nonce.' );
1087 return;
1088 }
1089
1090 var ajax_url = wpbc_bfb__get_ajax_url();
1091 if ( ! ajax_url ) {
1092 return;
1093 }
1094
1095 wpbc_bfb__button_busy_start( $btn );
1096 wpbc_admin_show_message_processing( '' );
1097
1098 jQuery.post( ajax_url, {
1099 action : action,
1100 nonce : nonce,
1101 mode : mode,
1102 skip_if_exists : skip_if_exists,
1103 set_bfb_form_not_defined: set_bfb_form_not_defined,
1104 } )
1105 .done( function ( resp ) {
1106
1107 if ( resp && resp.success && resp.data ) {
1108
1109 var msg = resp.data.message || 'Legacy forms import finished.';
1110 wpbc_admin_show_message( msg, 'success', 6000, false );
1111
1112 if ( resp.data.imported ) {
1113 // Reload current form, if imported some forms.
1114 wpbc_bfb__ajax_load_current_form( null );
1115 }
1116
1117 try {
1118 jQuery( document ).trigger( 'wpbc_bfb_legacy_forms_imported', [ resp.data ] );
1119 } catch ( _e ) {}
1120
1121 } else {
1122 wpbc_admin_show_message( 'WPBC BFB: legacy forms import error', 'error', 10000 );
1123 console.error( 'WPBC BFB: legacy forms import error', resp );
1124 }
1125 } )
1126 .fail( function ( xhr ) {
1127 wpbc_admin_show_message( 'WPBC BFB: legacy forms AJAX error', 'error', 10000 );
1128 console.error( 'WPBC BFB: legacy forms AJAX error', xhr.status, xhr.statusText );
1129 } )
1130 .always( function () {
1131 wpbc_bfb__button_busy_end( $btn );
1132 } );
1133
1134 } catch ( e ) {
1135 wpbc_admin_show_message( 'WPBC BFB: legacy forms import exception', 'error', 10000 );
1136 console.error( 'WPBC BFB: legacy forms import exception', e );
1137 }
1138 }
1139