PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 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 All 205 releases
← All changes | includes/page-form-builder/form-settings/_src/settings_effects.js +1302 -383 11.2 → 11.9 View file →
@@ -1,383 +1,1302 @@
1 -/**
2 - * Applies effects in Canvas, after changing some settings in the right sidebar in BFB.
3 - *
4 - * @file ../includes/page-form-builder/form-settings/_src/settings_effects.js
5 - */
6 -(function (w, d) {
7 - 'use strict';
8 -
9 - const Effects = (w.WPBC_BFB_Settings_Effects = w.WPBC_BFB_Settings_Effects || {});
10 - const map = (Effects.map = Effects.map || Object.create( null ));
11 -
12 - Effects.register = function (key, fn) {
13 - if ( key && typeof fn === 'function' ) {
14 - map[String( key )] = fn;
15 - }
16 - };
17 -
18 - function get_canvas_root() {
19 - return (
20 - d.querySelector( '#wpbc_bfb__pages_container' ) ||
21 - d.querySelector( '.wpbc_bfb__panel--preview' ) ||
22 - d.getElementById( 'wpbc_bfb__preview' ) ||
23 - d.body || d.documentElement
24 - );
25 - }
26 -
27 - Effects.apply_one = function (key, value, ctx) {
28 - const fn = map[String( key )];
29 - if ( ! fn ) {
30 - return;
31 - }
32 - try {
33 - fn( value, Object.assign( { key, value, canvas: get_canvas_root() }, ctx || {} ) );
34 - } catch ( e ) {
35 - // keep silent in production if you prefer
36 - console.error( 'WPBC Effects error:', key, e );
37 - }
38 - };
39 -
40 - Effects.apply_all = function (options, ctx) {
41 - if ( ! options || typeof options !== 'object' ) {
42 - return;
43 - }
44 - Object.keys( options ).forEach( function (k) {
45 - Effects.apply_one( k, options[k], ctx );
46 - } );
47 - };
48 -
49 - /**
50 - * Normalize settings pack to the minimum required shape:
51 - * { options: {}, css_vars: {} }
52 - *
53 - * @param {*} pack
54 - * @return {{options:Object, css_vars:Object, bfb_options?:Object}|null}
55 - */
56 - Effects.normalize_pack = function (pack) {
57 -
58 - if ( pack === null || typeof pack === 'undefined' || pack === '' ) {
59 - return null;
60 - }
61 -
62 - // Parse JSON string if needed.
63 - if ( typeof pack === 'string' ) {
64 - try {
65 - pack = JSON.parse( pack );
66 - } catch ( _e ) {
67 - return null;
68 - }
69 - }
70 -
71 - if ( ! pack || typeof pack !== 'object' ) {
72 - return null;
73 - }
74 -
75 - // If user passed just {key:value} options map, wrap it.
76 - const has_shape =
77 - Object.prototype.hasOwnProperty.call( pack, 'options' ) ||
78 - Object.prototype.hasOwnProperty.call( pack, 'css_vars' ) ||
79 - Object.prototype.hasOwnProperty.call( pack, 'bfb_options' );
80 -
81 - if ( ! has_shape ) {
82 - pack = { options: pack, css_vars: {} };
83 - }
84 -
85 - if ( ! pack.options || typeof pack.options !== 'object' ) {
86 - pack.options = {};
87 - }
88 - if ( ! pack.css_vars || typeof pack.css_vars !== 'object' ) {
89 - pack.css_vars = {};
90 - }
91 -
92 - // bfb_options is optional; keep if valid.
93 - if ( pack.bfb_options && typeof pack.bfb_options !== 'object' ) {
94 - delete pack.bfb_options;
95 - }
96 -
97 - return pack;
98 - };
99 -
100 - /**
101 - * Re-apply settings effects after a canvas rebuild / structure load.
102 - *
103 - * This is needed because structure loading can replace DOM nodes that effects target.
104 - *
105 - * @param {*} settings_pack string|object settings_json pack (or plain options map)
106 - * @param {Object} [ctx]
107 - */
108 - Effects.reapply_after_canvas = function (settings_pack, ctx) {
109 -
110 - const pack = Effects.normalize_pack( settings_pack );
111 - if ( ! pack ) {
112 - return;
113 - }
114 -
115 - // Apply immediately (best effort).
116 - Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas' }, ctx || {} ) );
117 -
118 - // Some modules/hydration may run shortly after; do one more pass.
119 - setTimeout( function () {
120 - Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas_delayed' }, ctx || {} ) );
121 - }, 60 );
122 - };
123 -
124 - // 1) Apply from AJAX load.
125 - d.addEventListener( 'wpbc:bfb:form_settings:apply', function (e) {
126 - const pack = e && e.detail ? e.detail.settings : null;
127 - if ( pack && pack.options ) {
128 - Effects.apply_all( pack.options, { source: 'apply' } );
129 - }
130 - } );
131 -
132 - // 2) Apply live from UI change (delegated).
133 - function css_escape(value) {
134 - const v = String( value == null ? '' : value );
135 - if ( w.CSS && typeof w.CSS.escape === 'function' ) {
136 - return w.CSS.escape( v );
137 - }
138 - return v.replace( /[^a-zA-Z0-9_\-]/g, '\\$&' );
139 - }
140 -
141 - function find_fs_root(el) {
142 - if ( ! el || ! el.closest ) {
143 - return null;
144 - }
145 -
146 - // 1) Direct: element or ancestor carries FS key (input/select/textarea writer, radio wrapper, etc.)
147 - const direct = el.closest( '[data-wpbc-bfb-fs-key]' );
148 - if ( direct ) {
149 - return direct;
150 - }
151 -
152 - // 2) Length: event came from number/unit/range inside .wpbc_slider_len_group
153 - const len_group = el.closest( '.wpbc_slider_len_group' );
154 - if ( len_group ) {
155 - return (
156 - len_group.querySelector( 'input[data-wpbc_slider_len_writer][data-wpbc-bfb-fs-key]' ) ||
157 - len_group.querySelector( 'input[data-wpbc-bfb-fs-type="length"][data-wpbc-bfb-fs-key]' ) ||
158 - null
159 - );
160 - }
161 -
162 - // 3) Range: event came from range input inside .wpbc_slider_range_group
163 - const range_group = el.closest( '.wpbc_slider_range_group' );
164 - if ( range_group ) {
165 - return (
166 - range_group.querySelector( 'input[data-wpbc_slider_range_writer][data-wpbc-bfb-fs-key]' ) ||
167 - range_group.querySelector( 'input[data-wpbc_slider_range_writer]' ) ||
168 - null
169 - );
170 - }
171 -
172 - return null;
173 - }
174 -
175 - function read_value_from_fs_root(fs_root, original_target) {
176 - if ( ! fs_root ) {
177 - return '';
178 - }
179 -
180 - const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );
181 -
182 - // RADIO: read checked within wrapper.
183 - if ( fs_type === 'radio' ) {
184 - const control_id = fs_root.getAttribute( 'data-wpbc-bfb-fs-controlid' ) || '';
185 - const selector = control_id
186 - ? 'input[type="radio"][name="' + css_escape( control_id ) + '"]:checked'
187 - : 'input[type="radio"]:checked';
188 -
189 - const checked = fs_root.querySelector( selector );
190 - return checked ? String( checked.value || '' ) : '';
191 - }
192 -
193 - // CHECKBOX / TOGGLE
194 - if ( (original_target && original_target.type === 'checkbox') || fs_root.type === 'checkbox' ) {
195 - const cb = (original_target && original_target.type === 'checkbox') ? original_target : fs_root;
196 - return cb.checked ? 'On' : 'Off';
197 - }
198 -
199 - // DEFAULT: writer/input/textarea/select
200 - if ( fs_root.value != null ) {
201 - return String( fs_root.value );
202 - }
203 - if ( original_target && original_target.value != null ) {
204 - return String( original_target.value );
205 - }
206 -
207 - return '';
208 - }
209 -
210 - function on_change(ev) {
211 - // Ignore events dispatched by code (apply/reapply, slider sync, etc.). Effects should react only to real user input + explicit wpbc:bfb:form_settings:apply.
212 - if ( ev && ev.isTrusted === false ) { return; }
213 - const target = ev && ev.target;
214 - if ( ! target ) { return; }
215 -
216 - const fs_root = find_fs_root( target );
217 - if ( ! fs_root ) { return; }
218 -
219 -
220 - // Normalize events so each control produces exactly one effect call.
221 - // - toggle/select/radio/checkbox => "change" only.
222 - // - everything else => "input" only.
223 - const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );
224 - const tag = String( target.tagName || '' ).toLowerCase();
225 - const type = String( target.type || '' ).toLowerCase();
226 -
227 - const use_change = (fs_type === 'toggle') || (fs_type === 'select') || (fs_type === 'radio') || (type === 'checkbox') || (type === 'radio') || (tag === 'select');
228 -
229 - if ( use_change && ev.type !== 'change' ) { return; }
230 - if ( ! use_change && ev.type !== 'input' ) { return; }
231 - // -------------------------------------------------------------------------------------------
232 -
233 - const key = fs_root.getAttribute( 'data-wpbc-bfb-fs-key' );
234 - if ( ! key ) { return; }
235 -
236 - const scope = fs_root.getAttribute( 'data-wpbc-bfb-fs-scope' ) || '';
237 - const value = read_value_from_fs_root( fs_root, target );
238 -
239 - Effects.apply_one( key, value, { source: 'ui', scope: scope, control: target, fs_root: fs_root } );
240 - }
241 -
242 - d.addEventListener( 'input', on_change, false );
243 - d.addEventListener( 'change', on_change, false );
244 -
245 -})( window, document );
246 -
247 -
248 -// BOOKING_FORM_THEME.
249 -WPBC_BFB_Settings_Effects.register( 'booking_form_theme', function (value, ctx) {
250 - // const root = ctx.canvas;
251 - const root = document.getElementById( 'wpbc_bfb__theme_scope' );
252 - if ( ! root || ! root.querySelectorAll ) {
253 - return;
254 - }
255 -
256 - // const wraps = root.querySelectorAll( '.wpbc_container.wpbc_form' );
257 - const wraps = root.querySelectorAll( '.wpbc_bfb__pages_panel' );
258 - if ( ! wraps.length ) {
259 - return;
260 - }
261 -
262 - wraps.forEach( function (wrap) {
263 - // remove any previous theme classes (simple + future-proof).
264 - Array.from( wrap.classList ).forEach( function (cls) {
265 - if ( /^wpbc_theme_/.test( cls ) ) {
266 - wrap.classList.remove( cls );
267 - }
268 - } );
269 -
270 - if ( value ) {
271 - wrap.classList.add( String( value ) );
272 - }
273 - } );
274 -} );
275 -
276 -
277 -// BOOKING_FORM_LAYOUT_WIDTH — Form width: applies combined "100%" / "600px" / "40rem" to the booking form containers.
278 -WPBC_BFB_Settings_Effects.register( 'booking_form_layout_width', function (value, ctx) {
279 - const root = ctx && ctx.canvas;
280 - if ( ! root || ! root.querySelectorAll ) {
281 - return;
282 - }
283 -
284 - const wraps = root.querySelectorAll( '.wpbc_bfb__form_preview_section_container' );
285 - if ( ! wraps.length ) {
286 - return;
287 - }
288 -
289 - const v = String( value == null ? '' : value ).trim();
290 -
291 - // allow only "number + unit".
292 - if ( v && ! /^-?\d+(?:\.\d+)?(?:%|px|rem|em|vw|vh)$/.test( v ) ) {
293 - return;
294 - }
295 -
296 - wraps.forEach(
297 - function (wrap) {
298 - if ( ! wrap || ! wrap.style ) {
299 - return;
300 - }
301 -
302 - if ( ! v ) {
303 - wrap.style.removeProperty( '--wpbc-bfb-booking_form_layout_width' );
304 - } else {
305 - wrap.style.setProperty( '--wpbc-bfb-booking_form_layout_width', v );
306 - }
307 - }
308 - );
309 -} );
310 -
311 -
312 -// Debug Preview Mode.
313 -WPBC_BFB_Settings_Effects.register( 'booking_bfb_preview_mode', function (value, ctx) {
314 - const root = ctx.canvas;
315 - if ( ! root || ! root.querySelectorAll ) {
316 - return;
317 - }
318 -
319 - const wraps = root.querySelectorAll( '.wpbc_container.wpbc_form' );
320 - if ( ! wraps.length ) {
321 - return;
322 - }
323 -
324 - // Get builder async.
325 - wpbc_bfb_api.with_builder(
326 - function (Builder) {
327 -
328 - /**
329 - * Capture active right sidebar tab and return restore handle.
330 - *
331 - * @return {{restore:function():void}|null}
332 - */
333 - function capture_right_sidebar_active_tab_restore_handle() {
334 -
335 - var tablist_el = document.querySelector( '.wpbc_bfb__rightbar_tabs[role="tablist"]' );
336 - if ( ! tablist_el ) {
337 - return null;
338 - }
339 -
340 - var active_tab_el = tablist_el.querySelector( '[role="tab"][aria-selected="true"]' );
341 -
342 - if ( ! active_tab_el ) {
343 - active_tab_el = tablist_el.querySelector( '[role="tab"][aria-controls="wpbc_bfb__palette_add_new"]' );
344 - }
345 -
346 - if ( ! active_tab_el || typeof active_tab_el.click !== 'function' ) {
347 - return null;
348 - }
349 -
350 - return {
351 - restore: function () {
352 - try { active_tab_el.click(); } catch ( _e ) {}
353 - }
354 - };
355 - }
356 -
357 - var tab_restore_handle = capture_right_sidebar_active_tab_restore_handle();
358 -
359 - let restored = false;
360 - var EVS = window.WPBC_BFB_Core && window.WPBC_BFB_Core.WPBC_BFB_Events ? window.WPBC_BFB_Core.WPBC_BFB_Events : {};
361 - var EV_DONE = EVS.STRUCTURE_LOADED || EVS.CANVAS_REFRESHED || 'wpbc:bfb:structure-loaded';
362 -
363 -
364 - function do_restore() {
365 - if ( restored ) { return; }
366 - restored = true;
367 - try { Builder?.bus?.off?.( EV_DONE, do_restore ); } catch ( _ ) {}
368 - requestAnimationFrame( function () {
369 - if ( ! tab_restore_handle ) { return; }
370 - tab_restore_handle.restore();
371 - } );
372 - }
373 -
374 - // Listen once (best), plus a fallback in case event isn't fired.
375 - try { Builder?.bus?.on?.( EV_DONE, do_restore ); } catch ( _ ) {}
376 -
377 -
378 - var enabled = ('On' === value);
379 - Builder.set_preview_mode( enabled, { rebuild: true, reinit: true, source: 'settings-effects' } );
380 - }
381 - );
382 -
383 -} );
1 +/**
2 + * Applies effects in Canvas, after changing some settings in the right sidebar in BFB.
3 + *
4 + * @file ../includes/page-form-builder/form-settings/_src/settings_effects.js
5 + */
6 +(function (w, d) {
7 + 'use strict';
8 +
9 + const Effects = (w.WPBC_BFB_Settings_Effects = w.WPBC_BFB_Settings_Effects || {});
10 + const map = (Effects.map = Effects.map || Object.create( null ));
11 +
12 + Effects.register = function (key, fn) {
13 + if ( key && typeof fn === 'function' ) {
14 + map[String( key )] = fn;
15 + }
16 + };
17 +
18 + function get_canvas_root() {
19 + return (
20 + d.querySelector( '#wpbc_bfb__pages_container' ) ||
21 + d.querySelector( '.wpbc_bfb__panel--preview' ) ||
22 + d.getElementById( 'wpbc_bfb__preview' ) ||
23 + d.body || d.documentElement
24 + );
25 + }
26 +
27 + Effects.apply_one = function (key, value, ctx) {
28 + const fn = map[String( key )];
29 + if ( ! fn ) {
30 + return;
31 + }
32 + try {
33 + fn( value, Object.assign( { key, value, canvas: get_canvas_root() }, ctx || {} ) );
34 + } catch ( e ) {
35 + // keep silent in production if you prefer
36 + console.error( 'WPBC Effects error:', key, e );
37 + }
38 + };
39 +
40 + Effects.apply_all = function (options, ctx) {
41 + if ( ! options || typeof options !== 'object' ) {
42 + return;
43 + }
44 + Object.keys( options ).forEach( function (k) {
45 + Effects.apply_one( k, options[k], Object.assign( { options: options }, ctx || {} ) );
46 + } );
47 + };
48 +
49 + /**
50 + * Normalize settings pack to the minimum required shape:
51 + * { options: {}, css_vars: {} }
52 + *
53 + * @param {*} pack
54 + * @return {{options:Object, css_vars:Object, bfb_options?:Object}|null}
55 + */
56 + Effects.normalize_pack = function (pack) {
57 +
58 + if ( pack === null || typeof pack === 'undefined' || pack === '' ) {
59 + return null;
60 + }
61 +
62 + // Parse JSON string if needed.
63 + if ( typeof pack === 'string' ) {
64 + try {
65 + pack = JSON.parse( pack );
66 + } catch ( _e ) {
67 + return null;
68 + }
69 + }
70 +
71 + if ( ! pack || typeof pack !== 'object' ) {
72 + return null;
73 + }
74 +
75 + // If user passed just {key:value} options map, wrap it.
76 + const has_shape =
77 + Object.prototype.hasOwnProperty.call( pack, 'options' ) ||
78 + Object.prototype.hasOwnProperty.call( pack, 'css_vars' ) ||
79 + Object.prototype.hasOwnProperty.call( pack, 'bfb_options' );
80 +
81 + if ( ! has_shape ) {
82 + pack = { options: pack, css_vars: {} };
83 + }
84 +
85 + if ( ! pack.options || typeof pack.options !== 'object' ) {
86 + pack.options = {};
87 + }
88 + if ( ! pack.css_vars || typeof pack.css_vars !== 'object' ) {
89 + pack.css_vars = {};
90 + }
91 +
92 + // bfb_options is optional; keep if valid.
93 + if ( pack.bfb_options && typeof pack.bfb_options !== 'object' ) {
94 + delete pack.bfb_options;
95 + }
96 +
97 + return pack;
98 + };
99 +
100 + /**
101 + * Re-apply settings effects after a canvas rebuild / structure load.
102 + *
103 + * This is needed because structure loading can replace DOM nodes that effects target.
104 + *
105 + * @param {*} settings_pack string|object settings_json pack (or plain options map)
106 + * @param {Object} [ctx]
107 + */
108 + Effects.reapply_after_canvas = function (settings_pack, ctx) {
109 +
110 + const pack = Effects.normalize_pack( settings_pack );
111 + if ( ! pack ) {
112 + return;
113 + }
114 +
115 + // Apply immediately (best effort).
116 + Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas' }, ctx || {} ) );
117 + wpbc_bfb_global_form_style__apply( null, Object.assign( { source: 'reapply_after_canvas' }, ctx || {} ) );
118 +
119 + // Some modules/hydration may run shortly after; do one more pass.
120 + setTimeout( function () {
121 + Effects.apply_all( pack.options, Object.assign( { source: 'reapply_after_canvas_delayed' }, ctx || {} ) );
122 + wpbc_bfb_global_form_style__apply( null, Object.assign( { source: 'reapply_after_canvas_delayed' }, ctx || {} ) );
123 + }, 60 );
124 + };
125 +
126 + // 1) Apply from AJAX load.
127 + d.addEventListener( 'wpbc:bfb:form_settings:apply', function (e) {
128 + const pack = e && e.detail ? e.detail.settings : null;
129 + if ( pack && pack.options ) {
130 + Effects.apply_all( pack.options, { source: 'apply' } );
131 + }
132 + wpbc_bfb_global_form_style__apply( null, { source: 'apply-global-style' } );
133 + } );
134 +
135 + // 2) Apply live from UI change (delegated).
136 + function css_escape(value) {
137 + const v = String( value == null ? '' : value );
138 + if ( w.CSS && typeof w.CSS.escape === 'function' ) {
139 + return w.CSS.escape( v );
140 + }
141 + return v.replace( /[^a-zA-Z0-9_\-]/g, '\\$&' );
142 + }
143 +
144 + function find_fs_root(el) {
145 + if ( ! el || ! el.closest ) {
146 + return null;
147 + }
148 +
149 + // 1) Direct: element or ancestor carries FS key (input/select/textarea writer, radio wrapper, etc.)
150 + const direct = el.closest( '[data-wpbc-bfb-fs-key]' );
151 + if ( direct ) {
152 + return direct;
153 + }
154 +
155 + // 2) Length: event came from number/unit/range inside .wpbc_slider_len_group
156 + const len_group = el.closest( '.wpbc_slider_len_group' );
157 + if ( len_group ) {
158 + return (
159 + len_group.querySelector( 'input[data-wpbc_slider_len_writer][data-wpbc-bfb-fs-key]' ) ||
160 + len_group.querySelector( 'input[data-wpbc-bfb-fs-type="length"][data-wpbc-bfb-fs-key]' ) ||
161 + null
162 + );
163 + }
164 +
165 + // 3) Spacing: event came from vertical/horizontal number inside .wpbc_spacing_group.
166 + const spacing_group = el.closest( '.wpbc_spacing_group' );
167 + if ( spacing_group ) {
168 + return (
169 + spacing_group.querySelector( 'input[data-wpbc_spacing_writer][data-wpbc-bfb-fs-key]' ) ||
170 + spacing_group.querySelector( 'input[data-wpbc-bfb-fs-type="spacing"][data-wpbc-bfb-fs-key]' ) ||
171 + null
172 + );
173 + }
174 +
175 + // 4) Range: event came from range input inside .wpbc_slider_range_group
176 + const range_group = el.closest( '.wpbc_slider_range_group' );
177 + if ( range_group ) {
178 + return (
179 + range_group.querySelector( 'input[data-wpbc_slider_range_writer][data-wpbc-bfb-fs-key]' ) ||
180 + range_group.querySelector( 'input[data-wpbc_slider_range_writer]' ) ||
181 + null
182 + );
183 + }
184 +
185 + return null;
186 + }
187 +
188 + function read_value_from_fs_root(fs_root, original_target) {
189 + if ( ! fs_root ) {
190 + return '';
191 + }
192 +
193 + const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );
194 +
195 + // RADIO: read checked within wrapper.
196 + if ( fs_type === 'radio' ) {
197 + const control_id = fs_root.getAttribute( 'data-wpbc-bfb-fs-controlid' ) || '';
198 + const selector = control_id
199 + ? 'input[type="radio"][name="' + css_escape( control_id ) + '"]:checked'
200 + : 'input[type="radio"]:checked';
201 +
202 + const checked = fs_root.querySelector( selector );
203 + return checked ? String( checked.value || '' ) : '';
204 + }
205 +
206 + if ( fs_type === 'spacing' ) {
207 + const group = ( original_target && original_target.closest ) ? original_target.closest( '.wpbc_spacing_group' ) : fs_root.closest( '.wpbc_spacing_group' );
208 + const vertical_input = group ? group.querySelector( 'input[data-wpbc_spacing_vertical]' ) : null;
209 + const horizontal_input = group ? group.querySelector( 'input[data-wpbc_spacing_horizontal]' ) : null;
210 + const writer = group ? group.querySelector( 'input[data-wpbc_spacing_writer]' ) : null;
211 + const vertical = vertical_input ? String( vertical_input.value || '0' ) : '0';
212 + const horizontal = horizontal_input ? String( horizontal_input.value || vertical ) : vertical;
213 + const combined = wpbc_bfb_form_appearance__normalize_spacing_numbers( vertical, horizontal );
214 +
215 + if ( writer ) {
216 + writer.value = combined;
217 + }
218 +
219 + return combined;
220 + }
221 +
222 + // CHECKBOX / TOGGLE
223 + if ( (original_target && original_target.type === 'checkbox') || fs_root.type === 'checkbox' ) {
224 + const cb = (original_target && original_target.type === 'checkbox') ? original_target : fs_root;
225 + return cb.checked ? 'On' : 'Off';
226 + }
227 +
228 + // DEFAULT: writer/input/textarea/select
229 + if ( fs_root.value != null ) {
230 + return String( fs_root.value );
231 + }
232 + if ( original_target && original_target.value != null ) {
233 + return String( original_target.value );
234 + }
235 +
236 + return '';
237 + }
238 +
239 + function apply_change_from_target(target, event_type, event_source) {
240 + if ( ! target ) { return; }
241 +
242 + const fs_root = find_fs_root( target );
243 + if ( ! fs_root ) { return; }
244 +
245 +
246 + // Normalize events so each control produces exactly one effect call.
247 + // - toggle/select/radio/checkbox => "change" only.
248 + // - everything else => "input" only.
249 + const fs_type = String( fs_root.getAttribute( 'data-wpbc-bfb-fs-type' ) || '' );
250 + const tag = String( target.tagName || '' ).toLowerCase();
251 + const type = String( target.type || '' ).toLowerCase();
252 +
253 + const use_change = (fs_type === 'toggle') || (fs_type === 'select') || (fs_type === 'radio') || (type === 'checkbox') || (type === 'radio') || (tag === 'select');
254 +
255 + if ( use_change && event_type !== 'change' ) { return; }
256 + if ( ! use_change && event_type !== 'input' ) { return; }
257 + // -------------------------------------------------------------------------------------------
258 +
259 + const key = fs_root.getAttribute( 'data-wpbc-bfb-fs-key' );
260 + if ( ! key ) { return; }
261 +
262 + const scope = fs_root.getAttribute( 'data-wpbc-bfb-fs-scope' ) || '';
263 + const value = read_value_from_fs_root( fs_root, target );
264 +
265 + Effects.apply_one( key, value, { source: event_source || 'ui', scope: scope, control: target, fs_root: fs_root } );
266 + }
267 +
268 + function is_coloris_control(target) {
269 + if ( ! target || ! target.matches ) {
270 + return false;
271 + }
272 +
273 + return target.matches( '[data-wpbc-bfb-fs-type="color"], [data-inspector-type="color"], .wpbc_bfb_coloris' );
274 + }
275 +
276 + function on_change(ev) {
277 + // Ignore generic synthetic events dispatched by code (apply/reapply, slider sync, etc.).
278 + // Coloris dispatches synthetic input events while the user picks a color, so allow those color controls through.
279 + if ( ev && ev.isTrusted === false && ! is_coloris_control( ev.target ) ) { return; }
280 + apply_change_from_target( ev && ev.target, ev && ev.type, ( ev && ev.isTrusted === false ) ? 'coloris' : 'ui' );
281 + }
282 +
283 + d.addEventListener( 'input', on_change, false );
284 + d.addEventListener( 'change', on_change, false );
285 + function on_coloris_pick(ev) {
286 + const detail = ev && ev.detail ? ev.detail : {};
287 + const target = detail.currentEl || detail.el || detail.input || ev.target || null;
288 +
289 + if ( ! is_coloris_control( target ) ) {
290 + return;
291 + }
292 +
293 + if ( detail.color && target.value !== detail.color ) {
294 + target.value = detail.color;
295 + }
296 +
297 + apply_change_from_target( target, 'input', 'coloris' );
298 + }
299 + d.addEventListener( 'coloris:pick', on_coloris_pick, false );
300 + d.addEventListener( 'wpbc:bfb:coloris:change', on_coloris_pick, false );
301 +
302 +})( window, document );
303 +
304 +function wpbc_bfb_form_appearance__get_presets() {
305 + return {
306 + bordered: {
307 + background : '#ffffff',
308 + borderColor: '#cccccc',
309 + borderWidth: '1px',
310 + radius : '2px',
311 + padding : '10px 30px',
312 + shadow : 'rgba(0, 0, 0, 0.05) 0px 2px 6px 0px'
313 + },
314 + none : {
315 + background : 'transparent',
316 + borderColor: 'transparent',
317 + borderWidth: '0px',
318 + radius : '0px',
319 + padding : '0px',
320 + shadow : 'none'
321 + },
322 + soft : {
323 + background : '#f9f9fa',
324 + borderColor: '#fff',
325 + borderWidth: '3px',
326 + radius : '8px',
327 + padding : '20px',
328 + shadow : 'rgba(15, 23, 42, 0.06) 0px 4px 16px 0px'
329 + }
330 + };
331 +}
332 +
333 +function wpbc_bfb_form_appearance__is_dark_theme(options) {
334 + options = options && typeof options === 'object' ? options : {};
335 + return 'wpbc_theme_dark_1' === String( options.booking_form_theme || '' );
336 +}
337 +
338 +function wpbc_bfb_form_appearance__get_preset_for_options(style, options) {
339 + const presets = wpbc_bfb_form_appearance__get_presets();
340 +
341 + if ( ! wpbc_bfb_form_appearance__is_dark_theme( options ) ) {
342 + return presets[style] || presets.bordered;
343 + }
344 +
345 + if ( 'soft' === style ) {
346 + return {
347 + background : '#1f2937',
348 + borderColor: '#334155',
349 + borderWidth: '3px',
350 + radius : '8px',
351 + padding : '20px',
352 + shadow : 'rgba(0, 0, 0, 0.24) 0px 4px 16px 0px'
353 + };
354 + }
355 +
356 + return presets[style] || presets.bordered;
357 +}
358 +
359 +function wpbc_bfb_form_appearance__sanitize_color(value, fallback) {
360 + const v = String( value == null ? '' : value ).trim();
361 + if ( /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( v ) ) {
362 + return v;
363 + }
364 + if ( v === 'transparent' ) {
365 + return v;
366 + }
367 + return fallback;
368 +}
369 +
370 +function wpbc_bfb_form_appearance__sanitize_optional_color(value) {
371 + return wpbc_bfb_form_appearance__sanitize_color( value, '' );
372 +}
373 +
374 +/**
375 + * Resolve an opaque accent color with the PHP-localized installation default.
376 + *
377 + * The Form Style effects live outside the registration IIFE, so the default is
378 + * deliberately read from the shared localized payload at the point of use.
379 + * Invalid requested and localized values return an empty string, allowing the
380 + * caller to skip the accent overlay without throwing or producing invalid CSS.
381 + *
382 + * @param {*} value Requested accent color.
383 + * @return {string} Valid three- or six-digit hexadecimal color, or an empty string.
384 + */
385 +function wpbc_bfb_global_form_style__sanitize_accent_color(value) {
386 + const requested_color = String( value == null ? '' : value ).trim();
387 + if ( /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( requested_color ) ) {
388 + return requested_color;
389 + }
390 +
391 + const settings_vars = window.wpbc_bfb_settings_vars && typeof window.wpbc_bfb_settings_vars === 'object'
392 + ? window.wpbc_bfb_settings_vars
393 + : {};
394 + const accent_defaults = settings_vars.form_accent_defaults && typeof settings_vars.form_accent_defaults === 'object'
395 + ? settings_vars.form_accent_defaults
396 + : {};
397 + const default_color = String( accent_defaults.booking_form_accent_color || '' ).trim();
398 +
399 + return /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( default_color ) ? default_color : '';
400 +}
401 +
402 +function wpbc_bfb_form_appearance__sanitize_length(value, fallback) {
403 + const v = String( value == null ? '' : value ).trim();
404 + if ( /^\d+(?:\.\d+)?(?:px|rem|em|%)$/i.test( v ) ) {
405 + return v;
406 + }
407 + return fallback;
408 +}
409 +
410 +function wpbc_bfb_form_appearance__sanitize_spacing(value, fallback) {
411 + const v = String( value == null ? '' : value ).trim().replace( /\s+/g, ' ' );
412 + const parts = v ? v.split( ' ' ) : [];
413 + if ( parts.length < 1 || parts.length > 4 ) {
414 + return fallback;
415 + }
416 + for ( let i = 0; i < parts.length; i++ ) {
417 + if ( ! /^\d+(?:\.\d+)?(?:px|rem|em|%)$/i.test( parts[i] ) ) {
418 + return fallback;
419 + }
420 + }
421 + return parts.join( ' ' );
422 +}
423 +
424 +function wpbc_bfb_form_appearance__normalize_spacing_numbers(vertical, horizontal) {
425 + const v = String( vertical == null ? '' : vertical ).trim();
426 + const h = String( horizontal == null ? '' : horizontal ).trim();
427 + const vertical_num = /^\d+(?:\.\d+)?$/.test( v ) ? v : '0';
428 + const horizontal_num = /^\d+(?:\.\d+)?$/.test( h ) ? h : vertical_num;
429 +
430 + return vertical_num + 'px ' + horizontal_num + 'px';
431 +}
432 +
433 +function wpbc_bfb_form_appearance__collect_options(ctx, key, value) {
434 + let options = (ctx && ctx.options && typeof ctx.options === 'object') ? Object.assign( {}, ctx.options ) : {};
435 +
436 + if ( window.WPBC_BFB_FormSettings && typeof window.WPBC_BFB_FormSettings.collect === 'function' ) {
437 + options = Object.assign( window.WPBC_BFB_FormSettings.collect( 'form' ) || {}, options );
438 + }
439 +
440 + if ( key ) {
441 + options[String( key )] = value;
442 + }
443 +
444 + if ( wpbc_bfb_form_appearance__is_custom_control_key( key ) ) {
445 + options.booking_form_container_style = 'custom';
446 + wpbc_bfb_form_appearance__set_container_style_control( 'custom' );
447 + }
448 +
449 + return options;
450 +}
451 +
452 +function wpbc_bfb_form_appearance__get_custom_control_keys() {
453 + return [
454 + 'booking_form_background_color',
455 + 'booking_form_border_color',
456 + 'booking_form_border_width',
457 + 'booking_form_border_radius',
458 + 'booking_form_padding',
459 + 'booking_form_text_color',
460 + 'booking_form_field_background_color',
461 + 'booking_form_field_text_color',
462 + 'booking_form_field_border_color'
463 + ];
464 +}
465 +
466 +function wpbc_bfb_form_appearance__is_custom_control_key(key) {
467 + return wpbc_bfb_form_appearance__get_custom_control_keys().indexOf( String( key || '' ) ) !== -1;
468 +}
469 +
470 +function wpbc_bfb_form_appearance__set_container_style_control(value) {
471 + const control = document.querySelector( '[data-wpbc-bfb-fs-key="booking_form_container_style"]' );
472 + if ( ! control || control.value === value ) {
473 + return;
474 + }
475 +
476 + control.value = value;
477 +}
478 +
479 +function wpbc_bfb_form_appearance__set_radio_control(key, value) {
480 + const row = document.querySelector( '.wpbc_bfb__form_setting[data-key="' + key + '"]' );
481 + if ( ! row ) {
482 + return;
483 + }
484 +
485 + const wrap = row.querySelector( '.wpbc_bfb__form_setting_radio[data-wpbc-bfb-fs-controlid]' );
486 + const control_id = wrap ? String( wrap.getAttribute( 'data-wpbc-bfb-fs-controlid' ) || '' ) : '';
487 + const radios = control_id
488 + ? row.querySelectorAll( 'input[type="radio"][name="' + control_id + '"]' )
489 + : row.querySelectorAll( 'input[type="radio"]' );
490 +
491 + radios.forEach( function (radio) {
492 + const should_check = ( String( radio.value ) === String( value == null ? '' : value ) );
493 + radio.checked = should_check;
494 +
495 + const choice = radio.closest ? radio.closest( '.wpbc_theme_choice' ) : null;
496 + if ( choice ) {
497 + choice.classList.toggle( 'is-selected', should_check );
498 + }
499 + } );
500 +}
501 +
502 +function wpbc_bfb_form_appearance__set_select_control(key, value) {
503 + const control = document.querySelector( '[data-wpbc-bfb-fs-key="' + key + '"]' );
504 + if ( control ) {
505 + control.value = String( value == null ? '' : value );
506 + }
507 +}
508 +
509 +function wpbc_bfb_form_appearance__get_current_options() {
510 + return window.WPBC_BFB_FormSettings && typeof window.WPBC_BFB_FormSettings.collect === 'function'
511 + ? window.WPBC_BFB_FormSettings.collect( 'form' ) || {}
512 + : {};
513 +}
514 +
515 +function wpbc_bfb_form_appearance__get_style_value_from_options(options) {
516 + options = options && typeof options === 'object' ? options : {};
517 +
518 + const theme = String( options.booking_form_theme || '' );
519 + const style = String( options.booking_form_container_style || 'inherit' );
520 +
521 + if ( 'custom' === style ) {
522 + return 'custom';
523 + }
524 + if ( 'inherit' === style || '' === style ) {
525 + return 'inherit';
526 + }
527 +
528 + const prefix = ( 'wpbc_theme_dark_1' === theme ) ? 'dark' : 'light';
529 + if ( [ 'bordered', 'none', 'soft' ].indexOf( style ) === -1 ) {
530 + return prefix + '_bordered';
531 + }
532 +
533 + return prefix + '_' + style;
534 +}
535 +
536 +function wpbc_bfb_form_appearance__sync_form_style_control(options) {
537 + wpbc_bfb_form_appearance__set_radio_control( 'booking_form_style', wpbc_bfb_form_appearance__get_style_value_from_options( options ) );
538 +}
539 +
540 +function wpbc_bfb_form_appearance__resolve_form_style_choice(value) {
541 + const current_options = wpbc_bfb_form_appearance__get_current_options();
542 + const current_theme = String( current_options.booking_form_theme || '' );
543 + const choice = String( value || 'inherit' );
544 +
545 + if ( 'custom' === choice ) {
546 + return {
547 + booking_form_theme : current_theme,
548 + booking_form_container_style: 'custom'
549 + };
550 + }
551 + if ( 'inherit' === choice || '' === choice ) {
552 + return {
553 + booking_form_theme : '',
554 + booking_form_container_style: 'inherit'
555 + };
556 + }
557 +
558 + const parts = choice.split( '_' );
559 + const theme = ( 'dark' === parts[0] ) ? 'wpbc_theme_dark_1' : '';
560 + const style = parts[1] || 'bordered';
561 +
562 + return {
563 + booking_form_theme : theme,
564 + booking_form_container_style: ( [ 'bordered', 'none', 'soft' ].indexOf( style ) === -1 ) ? 'bordered' : style
565 + };
566 +}
567 +
568 +function wpbc_bfb_form_appearance__is_user_theme_switch(ctx) {
569 + const source = String( ctx && ctx.source ? ctx.source : '' );
570 + return [ 'ui', 'coloris' ].indexOf( source ) !== -1;
571 +}
572 +
573 +function wpbc_bfb_form_appearance__is_custom_style(options) {
574 + return String( options && options.booking_form_container_style ? options.booking_form_container_style : 'inherit' ) === 'custom';
575 +}
576 +
577 +function wpbc_bfb_form_appearance__sync_custom_controls(options) {
578 + const is_custom = wpbc_bfb_form_appearance__is_custom_style( options );
579 + const reset_row = document.querySelector( '[data-wpbc-bfb-custom-appearance-reset-row]' );
580 + const base_theme_row = document.querySelector( '.wpbc_bfb__form_setting[data-key="booking_form_theme"]' );
581 +
582 + wpbc_bfb_form_appearance__get_custom_control_keys().forEach( function (key) {
583 + const row = document.querySelector( '.wpbc_bfb__form_setting[data-key="' + key + '"]' );
584 + if ( ! row ) {
585 + return;
586 + }
587 + row.hidden = ! is_custom;
588 + row.setAttribute( 'aria-hidden', is_custom ? 'false' : 'true' );
589 + row.classList.toggle( 'is-hidden', ! is_custom );
590 + } );
591 +
592 + if ( reset_row ) {
593 + reset_row.hidden = ! is_custom;
594 + reset_row.setAttribute( 'aria-hidden', is_custom ? 'false' : 'true' );
595 + reset_row.classList.toggle( 'is-hidden', ! is_custom );
596 + }
597 +
598 + if ( base_theme_row ) {
599 + base_theme_row.hidden = ! is_custom;
600 + base_theme_row.setAttribute( 'aria-hidden', is_custom ? 'false' : 'true' );
601 + base_theme_row.classList.toggle( 'is-hidden', ! is_custom );
602 + }
603 +}
604 +
605 +function wpbc_bfb_form_appearance__resolve(options) {
606 + let style = String( options.booking_form_container_style || 'inherit' );
607 +
608 + if ( style === 'inherit' ) {
609 + const global_options = window.wpbc_bfb_settings_vars && window.wpbc_bfb_settings_vars.global_appearance
610 + ? window.wpbc_bfb_settings_vars.global_appearance
611 + : {};
612 + options = Object.assign( {}, global_options || {} );
613 + style = String( options.booking_form_container_style || 'bordered' );
614 + }
615 +
616 + if ( style === 'bordered' ) {
617 + return null;
618 + }
619 +
620 + if ( style !== 'custom' ) {
621 + return wpbc_bfb_form_appearance__get_preset_for_options( style, options );
622 + }
623 +
624 + return {
625 + background : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_background_color, '#ffffff' ),
626 + borderColor: wpbc_bfb_form_appearance__sanitize_color( options.booking_form_border_color, '#cccccc' ),
627 + borderWidth: wpbc_bfb_form_appearance__sanitize_length( options.booking_form_border_width, '1px' ),
628 + radius : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_border_radius, '2px' ),
629 + padding : wpbc_bfb_form_appearance__sanitize_spacing( options.booking_form_padding, '10px 30px' ),
630 + shadow : 'rgba(0, 0, 0, 0.05) 0px 2px 6px 0px'
631 + };
632 +}
633 +
634 +function wpbc_bfb_form_appearance__resolve_design_colors(options) {
635 + options = options && typeof options === 'object' ? options : {};
636 +
637 + if ( ! wpbc_bfb_form_appearance__is_custom_style( options ) ) {
638 + if (
639 + wpbc_bfb_form_appearance__is_dark_theme( options ) &&
640 + 'none' === String( options.booking_form_container_style || '' )
641 + ) {
642 + return {
643 + textColor : '#1d2327',
644 + fieldBackground: '',
645 + fieldText : '',
646 + fieldBorder : ''
647 + };
648 + }
649 + return {
650 + textColor : '',
651 + fieldBackground: '',
652 + fieldText : '',
653 + fieldBorder : ''
654 + };
655 + }
656 +
657 + return {
658 + textColor : wpbc_bfb_form_appearance__sanitize_optional_color( options.booking_form_text_color ),
659 + fieldBackground: wpbc_bfb_form_appearance__sanitize_optional_color( options.booking_form_field_background_color ),
660 + fieldText : wpbc_bfb_form_appearance__sanitize_optional_color( options.booking_form_field_text_color ),
661 + fieldBorder : wpbc_bfb_form_appearance__sanitize_optional_color( options.booking_form_field_border_color )
662 + };
663 +}
664 +
665 +function wpbc_bfb_form_appearance__apply_vars(value, ctx) {
666 + const options = wpbc_bfb_form_appearance__collect_options( ctx, ctx && ctx.key, value );
667 + const resolved = wpbc_bfb_form_appearance__resolve( options );
668 + const design = wpbc_bfb_form_appearance__resolve_design_colors( options );
669 + const is_custom = wpbc_bfb_form_appearance__is_custom_style( options );
670 + const root = ctx && ctx.canvas;
671 +
672 + wpbc_bfb_form_appearance__sync_form_style_control( options );
673 + wpbc_bfb_form_appearance__sync_custom_controls( options );
674 +
675 + if ( ! root || ! root.querySelectorAll ) {
676 + return;
677 + }
678 +
679 + const wraps = root.querySelectorAll( '.wpbc_bfb__form_preview_section_container, .wpbc_bfb_form' );
680 + if ( ! wraps.length ) {
681 + return;
682 + }
683 +
684 + wraps.forEach( function (wrap) {
685 + if ( ! wrap || ! wrap.style ) {
686 + return;
687 + }
688 + wrap.classList.toggle( 'wpbc_bfb_form_appearance_custom', is_custom );
689 + if ( ! resolved ) {
690 + wrap.style.removeProperty( '--wpbc-bfb-form-background' );
691 + wrap.style.removeProperty( '--wpbc-bfb-form-border-color' );
692 + wrap.style.removeProperty( '--wpbc-bfb-form-border-width' );
693 + wrap.style.removeProperty( '--wpbc-bfb-form-border-radius' );
694 + wrap.style.removeProperty( '--wpbc-bfb-form-padding' );
695 + wrap.style.removeProperty( '--wpbc-bfb-form-box-shadow' );
696 + } else {
697 + wrap.style.setProperty( '--wpbc-bfb-form-background', resolved.background );
698 + wrap.style.setProperty( '--wpbc-bfb-form-border-color', resolved.borderColor );
699 + wrap.style.setProperty( '--wpbc-bfb-form-border-width', resolved.borderWidth );
700 + wrap.style.setProperty( '--wpbc-bfb-form-border-radius', resolved.radius );
701 + wrap.style.setProperty( '--wpbc-bfb-form-padding', resolved.padding );
702 + wrap.style.setProperty( '--wpbc-bfb-form-box-shadow', resolved.shadow );
703 + }
704 +
705 + if ( design.textColor ) {
706 + wrap.style.setProperty( '--wpbc_form-label-color', design.textColor );
707 + wrap.style.setProperty( '--wpbc_form-label-sublabel-color', design.textColor );
708 + } else {
709 + wrap.style.removeProperty( '--wpbc_form-label-color' );
710 + wrap.style.removeProperty( '--wpbc_form-label-sublabel-color' );
711 + }
712 +
713 + if ( design.fieldBackground ) {
714 + wrap.style.setProperty( '--wpbc_form-field-background-color', design.fieldBackground );
715 + wrap.style.setProperty( '--wpbc_form-field-menu-color', design.fieldBackground );
716 + } else {
717 + wrap.style.removeProperty( '--wpbc_form-field-background-color' );
718 + wrap.style.removeProperty( '--wpbc_form-field-menu-color' );
719 + }
720 +
721 + if ( design.fieldText ) {
722 + wrap.style.setProperty( '--wpbc_form-field-text-color', design.fieldText );
723 + } else {
724 + wrap.style.removeProperty( '--wpbc_form-field-text-color' );
725 + }
726 +
727 + if ( design.fieldBorder ) {
728 + wrap.style.setProperty( '--wpbc_form-field-border-color', design.fieldBorder );
729 + wrap.style.setProperty( '--wpbc_form-field-border-color-spare', design.fieldBorder );
730 + } else {
731 + wrap.style.removeProperty( '--wpbc_form-field-border-color' );
732 + wrap.style.removeProperty( '--wpbc_form-field-border-color-spare' );
733 + }
734 + } );
735 +}
736 +
737 +function wpbc_bfb_global_form_style__get_vars() {
738 + return window.wpbc_bfb_settings_vars || {};
739 +}
740 +
741 +function wpbc_bfb_global_form_style__get_presets() {
742 + const vars = wpbc_bfb_global_form_style__get_vars();
743 + return vars.form_style_presets && typeof vars.form_style_presets === 'object' ? vars.form_style_presets : {};
744 +}
745 +
746 +function wpbc_bfb_global_form_style__get_custom_keys() {
747 + return [
748 + 'booking_form_custom_background_color',
749 + 'booking_form_custom_border_color',
750 + 'booking_form_custom_border_width',
751 + 'booking_form_custom_border_radius',
752 + 'booking_form_custom_padding_vertical',
753 + 'booking_form_custom_padding_horizontal',
754 + 'booking_form_custom_text_color',
755 + 'booking_form_custom_field_background_color',
756 + 'booking_form_custom_field_text_color',
757 + 'booking_form_custom_field_border_color',
758 + 'booking_form_custom_button_background_color',
759 + 'booking_form_custom_button_text_color',
760 + 'booking_form_custom_button_border_color',
761 + 'booking_form_custom_button_hover_background_color',
762 + 'booking_form_custom_button_hover_text_color',
763 + 'booking_form_custom_button_hover_border_color',
764 + 'booking_form_custom_secondary_button_background_color',
765 + 'booking_form_custom_secondary_button_text_color',
766 + 'booking_form_custom_secondary_button_border_color',
767 + 'booking_form_custom_secondary_button_hover_background_color',
768 + 'booking_form_custom_secondary_button_hover_text_color',
769 + 'booking_form_custom_secondary_button_hover_border_color',
770 + 'booking_form_custom_button_border_width',
771 + 'booking_form_custom_button_border_radius'
772 + ];
773 +}
774 +
775 +function wpbc_bfb_global_form_style__get_custom_defaults() {
776 + const vars = wpbc_bfb_global_form_style__get_vars();
777 + const localized = vars.custom_form_style_defaults && typeof vars.custom_form_style_defaults === 'object'
778 + ? vars.custom_form_style_defaults
779 + : {};
780 +
781 + return Object.assign( {
782 + booking_form_custom_background_color : '#ffffff',
783 + booking_form_custom_border_color : '#cccccc',
784 + booking_form_custom_border_width : '1px',
785 + booking_form_custom_border_radius : '2px',
786 + booking_form_custom_padding_vertical : '10px',
787 + booking_form_custom_padding_horizontal : '30px',
788 + booking_form_custom_text_color : '#1d2327',
789 + booking_form_custom_field_background_color : '#ffffff',
790 + booking_form_custom_field_text_color : '#3c434a',
791 + booking_form_custom_field_border_color : '#cccccc',
792 + booking_form_custom_button_background_color: '#066aab',
793 + booking_form_custom_button_text_color : '#ffffff',
794 + booking_form_custom_button_border_color : '#066aab',
795 + booking_form_custom_button_hover_background_color: '#055589',
796 + booking_form_custom_button_hover_text_color: '#ffffff',
797 + booking_form_custom_button_hover_border_color: '#055589',
798 + booking_form_custom_secondary_button_background_color: '#fdfdfd',
799 + booking_form_custom_secondary_button_text_color: '#444444',
800 + booking_form_custom_secondary_button_border_color: '#eeeeee',
801 + booking_form_custom_secondary_button_hover_background_color: '#fdfdfd',
802 + booking_form_custom_secondary_button_hover_text_color: '#444444',
803 + booking_form_custom_secondary_button_hover_border_color: '#4d91cd',
804 + booking_form_custom_button_border_width : '1px',
805 + booking_form_custom_button_border_radius : '3px'
806 + }, localized );
807 +}
808 +
809 +function wpbc_bfb_global_form_style__get_current_options(ctx, key, value) {
810 + const vars = wpbc_bfb_global_form_style__get_vars();
811 + let options = vars.global_form_style && typeof vars.global_form_style === 'object'
812 + ? Object.assign( {}, vars.global_form_style )
813 + : {};
814 +
815 + if ( window.WPBC_BFB_FormSettings && typeof window.WPBC_BFB_FormSettings.collect === 'function' ) {
816 + options = Object.assign( options, window.WPBC_BFB_FormSettings.collect( 'global' ) || {} );
817 + }
818 +
819 + if ( ctx && ctx.options && typeof ctx.options === 'object' ) {
820 + options = Object.assign( options, ctx.options );
821 + }
822 + if ( key ) {
823 + options[String( key )] = value;
824 + }
825 + if ( ! options.booking_form_style ) {
826 + options.booking_form_style = 'light_bordered';
827 + }
828 +
829 + return options;
830 +}
831 +
832 +function wpbc_bfb_global_form_style__mix_colors(color, target, amount) {
833 + let source = wpbc_bfb_global_form_style__sanitize_accent_color( color ).replace( '#', '' );
834 + const destination = wpbc_bfb_form_appearance__sanitize_color( target, '#000000' ).replace( '#', '' );
835 + const channels = [];
836 + if ( ! source ) {
837 + return '';
838 + }
839 + if ( source.length === 3 ) {
840 + source = source.replace( /./g, function (value) { return value + value; } );
841 + }
842 + for ( let index = 0; index < 3; index++ ) {
843 + const source_channel = parseInt( source.substr( index * 2, 2 ), 16 );
844 + const target_channel = parseInt( destination.substr( index * 2, 2 ), 16 );
845 + channels.push( Math.round( source_channel + ( ( target_channel - source_channel ) * amount ) ) );
846 + }
847 + return '#' + channels.map( function (channel) { return ( '0' + channel.toString( 16 ) ).slice( -2 ); } ).join( '' );
848 +}
849 +
850 +function wpbc_bfb_global_form_style__get_luminance(color) {
851 + let hex = wpbc_bfb_global_form_style__sanitize_accent_color( color ).replace( '#', '' );
852 + if ( ! hex ) {
853 + return 0;
854 + }
855 + if ( hex.length === 3 ) {
856 + hex = hex.replace( /./g, function (value) { return value + value; } );
857 + }
858 + const channels = [ 0, 1, 2 ].map( function (index) {
859 + const channel = parseInt( hex.substr( index * 2, 2 ), 16 ) / 255;
860 + return channel <= 0.03928 ? channel / 12.92 : Math.pow( ( channel + 0.055 ) / 1.055, 2.4 );
861 + } );
862 + return ( 0.2126 * channels[0] ) + ( 0.7152 * channels[1] ) + ( 0.0722 * channels[2] );
863 +}
864 +
865 +/**
866 + * Apply shared accent variables without masking explicit Custom button controls.
867 + *
868 + * @param {Object} css_vars Resolved base style variables.
869 + * @param {Object} options Current global style options.
870 + * @param {boolean} preserve_custom_button_colors Whether Custom button variables remain authoritative.
871 + * @return {Object} Resolved variables with the optional accent overlay.
872 + */
873 +function wpbc_bfb_global_form_style__apply_accent(css_vars, options, preserve_custom_button_colors) {
874 + if ( String( options.booking_form_accent_enabled || 'Off' ) !== 'On' ) {
875 + return css_vars;
876 + }
877 + const accent = wpbc_bfb_global_form_style__sanitize_accent_color( options.booking_form_accent_color );
878 + if ( ! accent ) {
879 + return css_vars;
880 + }
881 + const luminance = wpbc_bfb_global_form_style__get_luminance( accent );
882 + const contrast = luminance > 0.18 ? '#000000' : '#ffffff';
883 + const hover_target = '#ffffff' === contrast ? '#000000' : '#ffffff';
884 + const hover = wpbc_bfb_global_form_style__mix_colors( accent, hover_target, 0.10 );
885 + const hover_contrast = contrast;
886 +
887 + const accent_overlay = {
888 + '--wpbc_form-accent-color': accent,
889 + '--wpbc_form-accent-hover-color': hover,
890 + '--wpbc_form-accent-contrast-color': contrast,
891 + '--wpbc_form-field-focus-border-color': accent,
892 + '--wpbc_form-field-focus-shadow-color': accent,
893 + '--wpbc_form-choice-checked-border-color': accent,
894 + '--wpbc_form-choice-checked-color': accent,
895 + '--wpbc_form-choice-focus-color': accent,
896 + '--wpbc_form-button-background-color': accent,
897 + '--wpbc_form-button-background-color-alt': accent,
898 + '--wpbc_form-button-border-color': accent,
899 + '--wpbc_form-button-text-color': contrast,
900 + '--wpbc_form-button-text-color-alt': contrast,
901 + '--wpbc_form-button-hover-background-color': hover,
902 + '--wpbc_form-button-hover-border-color': hover,
903 + '--wpbc_form-button-hover-text-color': hover_contrast,
904 + '--wpbc_form-button-light-hover-border-color': accent,
905 + '--wpbc_form-button-primary-hover-border-color': hover,
906 + '--wpbc_form-page-break-color': accent
907 + };
908 +
909 + if ( preserve_custom_button_colors ) {
910 + [
911 + '--wpbc_form-button-background-color',
912 + '--wpbc_form-button-background-color-alt',
913 + '--wpbc_form-button-border-color',
914 + '--wpbc_form-button-text-color',
915 + '--wpbc_form-button-text-color-alt',
916 + '--wpbc_form-button-hover-background-color',
917 + '--wpbc_form-button-hover-border-color',
918 + '--wpbc_form-button-hover-text-color',
919 + '--wpbc_form-button-light-hover-border-color',
920 + '--wpbc_form-button-primary-hover-border-color'
921 + ].forEach( function (css_var_name) {
922 + delete accent_overlay[css_var_name];
923 + } );
924 + }
925 +
926 + return Object.assign( {}, css_vars, accent_overlay );
927 +}
928 +
929 +function wpbc_bfb_global_form_style__resolve_css_vars(options) {
930 + options = options && typeof options === 'object' ? options : {};
931 + const style = String( options.booking_form_style || 'light_bordered' );
932 + const presets = wpbc_bfb_global_form_style__get_presets();
933 + const preset = presets[style] || presets.light_bordered || {};
934 + const defaults = wpbc_bfb_global_form_style__get_custom_defaults();
935 +
936 + if ( 'custom' !== style ) {
937 + return wpbc_bfb_global_form_style__apply_accent( preset.css_vars && typeof preset.css_vars === 'object' ? Object.assign( {}, preset.css_vars ) : {}, options );
938 + }
939 +
940 + const css_vars = {
941 + '--wpbc-bfb-form-background' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_background_color, defaults.booking_form_custom_background_color ),
942 + '--wpbc-bfb-form-border-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_border_color, defaults.booking_form_custom_border_color ),
943 + '--wpbc-bfb-form-border-width' : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_border_width, defaults.booking_form_custom_border_width ),
944 + '--wpbc-bfb-form-border-radius' : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_border_radius, defaults.booking_form_custom_border_radius ),
945 + '--wpbc-bfb-form-padding' : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_padding_vertical, defaults.booking_form_custom_padding_vertical ) + ' ' + wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_padding_horizontal, defaults.booking_form_custom_padding_horizontal ),
946 + '--wpbc-bfb-form-box-shadow' : 'rgba(0, 0, 0, 0.05) 0px 2px 6px 0px',
947 + '--wpbc_form-label-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_text_color, defaults.booking_form_custom_text_color ),
948 + '--wpbc_form-label-sublabel-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_text_color, defaults.booking_form_custom_text_color ),
949 + '--wpbc_form-label-error-color' : '#d63637',
950 + '--wpbc_form-field-background-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_field_background_color, defaults.booking_form_custom_field_background_color ),
951 + '--wpbc_form-field-menu-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_field_background_color, defaults.booking_form_custom_field_background_color ),
952 + '--wpbc_form-field-text-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_field_text_color, defaults.booking_form_custom_field_text_color ),
953 + '--wpbc_form-field-border-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_field_border_color, defaults.booking_form_custom_field_border_color ),
954 + '--wpbc_form-field-border-color-spare': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_field_border_color, defaults.booking_form_custom_field_border_color ),
955 + '--wpbc_form-field-focus-border-color': '#066aab',
956 + '--wpbc_form-field-focus-shadow-color': '#066aab',
957 + '--wpbc_form-field-disabled-color' : 'rgba(0, 0, 0, 0.2)',
958 + '--wpbc_form-button-border-radius' : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_button_border_radius, defaults.booking_form_custom_button_border_radius ),
959 + '--wpbc_form-button-border-style' : 'solid',
960 + '--wpbc_form-button-border-size' : wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_button_border_width, defaults.booking_form_custom_button_border_width ),
961 + '--wpbc_form-button-background-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_background_color, defaults.booking_form_custom_button_background_color ),
962 + '--wpbc_form-button-background-color-alt': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_background_color, defaults.booking_form_custom_button_background_color ),
963 + '--wpbc_form-button-border-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_border_color, defaults.booking_form_custom_button_border_color ),
964 + '--wpbc_form-button-text-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_text_color, defaults.booking_form_custom_button_text_color ),
965 + '--wpbc_form-button-text-color-alt' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_text_color, defaults.booking_form_custom_button_text_color ),
966 + '--wpbc_form-button-hover-background-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_hover_background_color, defaults.booking_form_custom_button_hover_background_color ),
967 + '--wpbc_form-button-hover-border-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_hover_border_color, defaults.booking_form_custom_button_hover_border_color ),
968 + '--wpbc_form-button-hover-text-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_hover_text_color, defaults.booking_form_custom_button_hover_text_color ),
969 + '--wpbc_form-choice-checked-border-color': '#066aab',
970 + '--wpbc_form-choice-checked-color' : '#066aab',
971 + '--wpbc_form-choice-focus-color' : '#066aab',
972 + '--wpbc_form-button-light-background-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_background_color, defaults.booking_form_custom_secondary_button_background_color ),
973 + '--wpbc_form-button-light-border-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_border_color, defaults.booking_form_custom_secondary_button_border_color ),
974 + '--wpbc_form-button-light-border-size': wpbc_bfb_form_appearance__sanitize_length( options.booking_form_custom_button_border_width, defaults.booking_form_custom_button_border_width ),
975 + '--wpbc_form-button-light-text-color' : wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_text_color, defaults.booking_form_custom_secondary_button_text_color ),
976 + '--wpbc_form-button-light-box-shadow' : '0 2px 10px 2px #ffffff54',
977 + '--wpbc_form-button-light-hover-background-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_hover_background_color, defaults.booking_form_custom_secondary_button_hover_background_color ),
978 + '--wpbc_form-button-light-hover-border-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_hover_border_color, defaults.booking_form_custom_secondary_button_hover_border_color ),
979 + '--wpbc_form-button-light-hover-text-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_secondary_button_hover_text_color, defaults.booking_form_custom_secondary_button_hover_text_color ),
980 + '--wpbc_form-button-light-hover-box-shadow': '0 2px 10px 2px #ffffff54',
981 + '--wpbc_form-button-primary-hover-border-color': wpbc_bfb_form_appearance__sanitize_color( options.booking_form_custom_button_hover_border_color, defaults.booking_form_custom_button_hover_border_color ),
982 + '--wpbc_form-page-break-color' : '#066aab'
983 + };
984 +
985 + return wpbc_bfb_global_form_style__apply_accent( css_vars, options, true );
986 +}
987 +
988 +function wpbc_bfb_global_form_style__get_css_var_keys(options) {
989 + const vars = wpbc_bfb_global_form_style__get_vars();
990 + const localized = Array.isArray( vars.form_style_css_var_names ) ? vars.form_style_css_var_names : [];
991 + const keys = [];
992 + const presets = wpbc_bfb_global_form_style__get_presets();
993 +
994 + if ( localized.length ) {
995 + return localized;
996 + }
997 +
998 + Object.keys( presets ).forEach( function (preset_key) {
999 + const preset = presets[preset_key] || {};
1000 + const css_vars = preset.css_vars && typeof preset.css_vars === 'object' ? preset.css_vars : {};
1001 +
1002 + Object.keys( css_vars ).forEach( function (var_name) {
1003 + if ( keys.indexOf( var_name ) === -1 ) {
1004 + keys.push( var_name );
1005 + }
1006 + } );
1007 + } );
1008 +
1009 + Object.keys( wpbc_bfb_global_form_style__resolve_css_vars( Object.assign( {}, options || {}, { booking_form_style: 'custom' } ) ) ).forEach( function (var_name) {
1010 + if ( keys.indexOf( var_name ) === -1 ) {
1011 + keys.push( var_name );
1012 + }
1013 + } );
1014 +
1015 + return keys;
1016 +}
1017 +
1018 +function wpbc_bfb_global_form_style__sync_controls(options) {
1019 + const is_custom = 'custom' === String( options && options.booking_form_style ? options.booking_form_style : '' );
1020 + const accent_enabled = 'On' === String( options && options.booking_form_accent_enabled ? options.booking_form_accent_enabled : 'Off' );
1021 + const reset_row = document.querySelector( '[data-wpbc-bfb-custom-appearance-reset-row]' );
1022 +
1023 + wpbc_bfb_form_appearance__set_radio_control( 'booking_form_style', options.booking_form_style || 'light_bordered' );
1024 +
1025 + document.querySelectorAll( '.wpbc_bfb__form_setting_global_custom_style' ).forEach( function (row) {
1026 + row.hidden = ! is_custom;
1027 + row.setAttribute( 'aria-hidden', is_custom ? 'false' : 'true' );
1028 + row.classList.toggle( 'is-hidden', ! is_custom );
1029 + } );
1030 +
1031 + document.querySelectorAll( '.wpbc_bfb__form_setting_global_accent_dependent' ).forEach( function (row) {
1032 + row.hidden = ! accent_enabled;
1033 + row.setAttribute( 'aria-hidden', accent_enabled ? 'false' : 'true' );
1034 + row.classList.toggle( 'is-hidden', ! accent_enabled );
1035 + } );
1036 +
1037 + if ( reset_row ) {
1038 + reset_row.hidden = ! is_custom;
1039 + reset_row.setAttribute( 'aria-hidden', is_custom ? 'false' : 'true' );
1040 + reset_row.classList.toggle( 'is-hidden', ! is_custom );
1041 + }
1042 +}
1043 +
1044 +function wpbc_bfb_global_form_style__apply(value, ctx) {
1045 + const options = wpbc_bfb_global_form_style__get_current_options( ctx, ctx && ctx.key, value );
1046 + const style = String( options.booking_form_style || 'light_bordered' );
1047 + const presets = wpbc_bfb_global_form_style__get_presets();
1048 + const preset = presets[style] || presets.light_bordered || {};
1049 + const css_vars = wpbc_bfb_global_form_style__resolve_css_vars( options );
1050 + // Form Style is global. Always start at the complete Builder theme scope so
1051 + // inline Custom tokens on an outer wrapper cannot leak into a preset when a
1052 + // field-level update provides only the inner canvas in ctx.canvas.
1053 + const root = document.getElementById( 'wpbc_bfb__theme_scope' ) || ( ctx && ctx.canvas ) || document;
1054 + const theme_classes = [];
1055 + const css_var_keys = wpbc_bfb_global_form_style__get_css_var_keys( options );
1056 +
1057 + wpbc_bfb_global_form_style__sync_controls( options );
1058 +
1059 + Object.keys( presets ).forEach( function (preset_key) {
1060 + const class_name = presets[preset_key] && presets[preset_key].theme_class ? String( presets[preset_key].theme_class ) : '';
1061 + if ( class_name && theme_classes.indexOf( class_name ) === -1 ) {
1062 + theme_classes.push( class_name );
1063 + }
1064 + } );
1065 +
1066 + if ( ! root || ! root.querySelectorAll ) {
1067 + return;
1068 + }
1069 +
1070 + const selector = '.wpbc_container.wpbc_form, .wpbc_bfb_form, .wpbc_bfb__pages_panel, .wpbc_bfb__form_preview_section_container';
1071 + const wraps = [];
1072 + if ( root.matches && root.matches( selector ) ) {
1073 + wraps.push( root );
1074 + }
1075 + root.querySelectorAll( selector ).forEach( function (wrap) {
1076 + wraps.push( wrap );
1077 + } );
1078 +
1079 + wraps.forEach( function (wrap) {
1080 + if ( ! wrap || ! wrap.style ) {
1081 + return;
1082 + }
1083 + theme_classes.forEach( function (class_name) {
1084 + wrap.classList.remove( class_name );
1085 + } );
1086 + if ( preset.theme_class ) {
1087 + wrap.classList.add( String( preset.theme_class ) );
1088 + }
1089 + wrap.classList.toggle( 'wpbc_bfb_form_appearance_custom', 'custom' === style );
1090 +
1091 + css_var_keys.forEach( function (css_key) {
1092 + wrap.style.removeProperty( css_key );
1093 + } );
1094 + Object.keys( css_vars ).forEach( function (css_key) {
1095 + wrap.style.setProperty( css_key, css_vars[css_key] );
1096 + } );
1097 + } );
1098 +}
1099 +
1100 +[
1101 + 'booking_form_style',
1102 + 'booking_form_accent_enabled',
1103 + 'booking_form_accent_color',
1104 + 'booking_form_custom_background_color',
1105 + 'booking_form_custom_border_color',
1106 + 'booking_form_custom_border_width',
1107 + 'booking_form_custom_border_radius',
1108 + 'booking_form_custom_padding_vertical',
1109 + 'booking_form_custom_padding_horizontal',
1110 + 'booking_form_custom_text_color',
1111 + 'booking_form_custom_field_background_color',
1112 + 'booking_form_custom_field_text_color',
1113 + 'booking_form_custom_field_border_color',
1114 + 'booking_form_custom_button_background_color',
1115 + 'booking_form_custom_button_text_color',
1116 + 'booking_form_custom_button_border_color',
1117 + 'booking_form_custom_button_hover_background_color',
1118 + 'booking_form_custom_button_hover_text_color',
1119 + 'booking_form_custom_button_hover_border_color',
1120 + 'booking_form_custom_secondary_button_background_color',
1121 + 'booking_form_custom_secondary_button_text_color',
1122 + 'booking_form_custom_secondary_button_border_color',
1123 + 'booking_form_custom_secondary_button_hover_background_color',
1124 + 'booking_form_custom_secondary_button_hover_text_color',
1125 + 'booking_form_custom_secondary_button_hover_border_color',
1126 + 'booking_form_custom_button_border_width',
1127 + 'booking_form_custom_button_border_radius'
1128 +].forEach( function (key) {
1129 + WPBC_BFB_Settings_Effects.register( key, function (value, ctx) {
1130 + wpbc_bfb_global_form_style__apply( value, Object.assign( {}, ctx || {}, { key: key } ) );
1131 + } );
1132 +} );
1133 +
1134 +function wpbc_bfb_form_appearance__sync_custom_controls_from_ui() {
1135 + const options = wpbc_bfb_global_form_style__get_current_options();
1136 + wpbc_bfb_global_form_style__sync_controls( options );
1137 + wpbc_bfb_global_form_style__apply( null, { source: 'sync-global-style' } );
1138 +}
1139 +
1140 +wpbc_bfb_form_appearance__sync_custom_controls_from_ui();
1141 +document.addEventListener( 'DOMContentLoaded', wpbc_bfb_form_appearance__sync_custom_controls_from_ui );
1142 +
1143 +
1144 +// BOOKING_FORM_THEME.
1145 +WPBC_BFB_Settings_Effects.register( 'booking_form_theme', function (value, ctx) {
1146 + const root = (ctx && ctx.canvas) || document.getElementById( 'wpbc_bfb__theme_scope' ) || document;
1147 + if ( ! root || ! root.querySelectorAll ) {
1148 + return;
1149 + }
1150 +
1151 + if ( wpbc_bfb_form_appearance__is_user_theme_switch( ctx ) ) {
1152 + const current_options = wpbc_bfb_form_appearance__get_current_options();
1153 + if ( 'custom' === String( current_options.booking_form_container_style || '' ) ) {
1154 + current_options.booking_form_theme = value;
1155 + wpbc_bfb_form_appearance__sync_form_style_control( current_options );
1156 + wpbc_bfb_form_appearance__apply_vars( 'custom', Object.assign( {}, ctx || {}, {
1157 + key : 'booking_form_container_style',
1158 + source : 'theme-base-custom',
1159 + options: current_options
1160 + } ) );
1161 + } else {
1162 + wpbc_bfb_form_appearance__set_container_style_control( 'bordered' );
1163 + wpbc_bfb_form_appearance__apply_vars( 'bordered', Object.assign( {}, ctx || {}, { key: 'booking_form_container_style' } ) );
1164 + }
1165 + } else if ( ctx && ctx.options ) {
1166 + wpbc_bfb_form_appearance__sync_form_style_control( ctx.options );
1167 + }
1168 +
1169 + const theme_selector = '.wpbc_container.wpbc_form, .wpbc_bfb_form, .wpbc_bfb__pages_panel';
1170 + const wraps = [];
1171 + if ( root.matches && root.matches( theme_selector ) ) {
1172 + wraps.push( root );
1173 + }
1174 + root.querySelectorAll( theme_selector ).forEach( function (wrap) {
1175 + wraps.push( wrap );
1176 + } );
1177 + if ( ! wraps.length ) {
1178 + return;
1179 + }
1180 +
1181 + wraps.forEach( function (wrap) {
1182 + // remove any previous theme classes (simple + future-proof).
1183 + Array.from( wrap.classList ).forEach( function (cls) {
1184 + if ( /^wpbc_theme_/.test( cls ) ) {
1185 + wrap.classList.remove( cls );
1186 + }
1187 + } );
1188 +
1189 + if ( value ) {
1190 + wrap.classList.add( String( value ) );
1191 + }
1192 + } );
1193 +} );
1194 +
1195 +
1196 +// BOOKING_FORM_LAYOUT_WIDTH — Form width: applies combined "100%" / "600px" / "40rem" to the booking form containers.
1197 +WPBC_BFB_Settings_Effects.register( 'booking_form_layout_width', function (value, ctx) {
1198 + const root = ctx && ctx.canvas;
1199 + if ( ! root || ! root.querySelectorAll ) {
1200 + return;
1201 + }
1202 +
1203 + const wraps = root.querySelectorAll( '.wpbc_bfb__form_preview_section_container' );
1204 + if ( ! wraps.length ) {
1205 + return;
1206 + }
1207 +
1208 + const v = String( value == null ? '' : value ).trim();
1209 +
1210 + // allow only "number + unit".
1211 + if ( v && ! /^\d+(?:\.\d+)?(?:%|px|rem|em|vw|vh)$/.test( v ) ) {
1212 + return;
1213 + }
1214 +
1215 + wraps.forEach(
1216 + function (wrap) {
1217 + if ( ! wrap || ! wrap.style ) {
1218 + return;
1219 + }
1220 +
1221 + if ( ! v ) {
1222 + wrap.style.removeProperty( '--wpbc-bfb-booking_form_layout_width' );
1223 + } else {
1224 + wrap.style.setProperty( '--wpbc-bfb-booking_form_layout_width', v );
1225 + }
1226 + }
1227 + );
1228 +} );
1229 +
1230 +
1231 +// Debug Preview Mode.
1232 +WPBC_BFB_Settings_Effects.register( 'booking_bfb_preview_mode', function (value, ctx) {
1233 + const root = ctx.canvas;
1234 + if ( ! root || ! root.querySelectorAll ) {
1235 + return;
1236 + }
1237 +
1238 + const wraps = root.querySelectorAll( '.wpbc_container.wpbc_form' );
1239 + if ( ! wraps.length ) {
1240 + return;
1241 + }
1242 +
1243 + // Get builder async.
1244 + wpbc_bfb_api.with_builder(
1245 + function (Builder) {
1246 +
1247 + /**
1248 + * Capture active right sidebar tab and return restore handle.
1249 + *
1250 + * @return {{restore:function():void}|null}
1251 + */
1252 + function capture_right_sidebar_active_tab_restore_handle() {
1253 +
1254 + var tablist_el = document.querySelector( '.wpbc_bfb__rightbar_tabs[role="tablist"]' );
1255 + if ( ! tablist_el ) {
1256 + return null;
1257 + }
1258 +
1259 + var active_tab_el = tablist_el.querySelector( '[role="tab"][aria-selected="true"]' );
1260 +
1261 + if ( ! active_tab_el ) {
1262 + active_tab_el = tablist_el.querySelector( '[role="tab"][aria-controls="wpbc_bfb__palette_add_new"]' );
1263 + }
1264 +
1265 + if ( ! active_tab_el || typeof active_tab_el.click !== 'function' ) {
1266 + return null;
1267 + }
1268 +
1269 + return {
1270 + restore: function () {
1271 + try { active_tab_el.click(); } catch ( _e ) {}
1272 + }
1273 + };
1274 + }
1275 +
1276 + var tab_restore_handle = capture_right_sidebar_active_tab_restore_handle();
1277 +
1278 + let restored = false;
1279 + var EVS = window.WPBC_BFB_Core && window.WPBC_BFB_Core.WPBC_BFB_Events ? window.WPBC_BFB_Core.WPBC_BFB_Events : {};
1280 + var EV_DONE = EVS.STRUCTURE_LOADED || EVS.CANVAS_REFRESHED || 'wpbc:bfb:structure-loaded';
1281 +
1282 +
1283 + function do_restore() {
1284 + if ( restored ) { return; }
1285 + restored = true;
1286 + try { Builder?.bus?.off?.( EV_DONE, do_restore ); } catch ( _ ) {}
1287 + requestAnimationFrame( function () {
1288 + if ( ! tab_restore_handle ) { return; }
1289 + tab_restore_handle.restore();
1290 + } );
1291 + }
1292 +
1293 + // Listen once (best), plus a fallback in case event isn't fired.
1294 + try { Builder?.bus?.on?.( EV_DONE, do_restore ); } catch ( _ ) {}
1295 +
1296 +
1297 + var enabled = ('On' === value);
1298 + Builder.set_preview_mode( enabled, { rebuild: true, reinit: true, source: 'settings-effects' } );
1299 + }
1300 + );
1301 +
1302 +} );