PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
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
← All changes | includes/page-form-builder/form-settings/_src/settings.js +481 -54 11.211.8.4 View file →
@@ -1,4 +1,4 @@
1 1 /* globals window, document */
2 2 (function (w, d) {
3 3 'use strict';
4 4
@@ -11,9 +11,11 @@
11 11 *
12 12 * Optional:
13 13 * - re-apply after Builder STRUCTURE_LOADED (timing hook only)
14 14 */
15 - const api = (w.WPBC_BFB_FormSettings = w.WPBC_BFB_FormSettings || {});
15 + const api = (w.WPBC_BFB_FormSettings = w.WPBC_BFB_FormSettings || {});
16 + let pending_time_picker_skin_button = null;
17 + let previous_time_picker_skin_url = '';
16 18
17 19 // Last received settings pack (from AJAX).
18 20 let last_settings_pack = null;
19 21
@@ -18,11 +20,51 @@
18 20 let last_settings_pack = null;
19 21
20 22 // Small retry, because DOM can be re-rendered after apply event.
21 23 let raf_id = 0;
22 - let retry_count = 0;
23 - const retry_max = 20;
24 -
24 + let retry_count = 0;
25 + const retry_max = 20;
26 + const fallback_form_style_option_keys = [
27 + 'booking_form_style',
28 + 'booking_form_accent_enabled',
29 + 'booking_form_accent_color',
30 + 'booking_form_custom_background_color',
31 + 'booking_form_custom_border_color',
32 + 'booking_form_custom_border_width',
33 + 'booking_form_custom_border_radius',
34 + 'booking_form_custom_padding_vertical',
35 + 'booking_form_custom_padding_horizontal',
36 + 'booking_form_custom_text_color',
37 + 'booking_form_custom_field_background_color',
38 + 'booking_form_custom_field_text_color',
39 + 'booking_form_custom_field_border_color',
40 + 'booking_form_custom_button_background_color',
41 + 'booking_form_custom_button_text_color',
42 + 'booking_form_custom_button_border_color',
43 + 'booking_form_custom_button_hover_background_color',
44 + 'booking_form_custom_button_hover_text_color',
45 + 'booking_form_custom_button_hover_border_color',
46 + 'booking_form_custom_secondary_button_background_color',
47 + 'booking_form_custom_secondary_button_text_color',
48 + 'booking_form_custom_secondary_button_border_color',
49 + 'booking_form_custom_secondary_button_hover_background_color',
50 + 'booking_form_custom_secondary_button_hover_text_color',
51 + 'booking_form_custom_secondary_button_hover_border_color',
52 + 'booking_form_custom_button_border_width',
53 + 'booking_form_custom_button_border_radius',
54 + 'booking_form_theme',
55 + 'booking_form_container_style',
56 + 'booking_form_background_color',
57 + 'booking_form_border_color',
58 + 'booking_form_border_width',
59 + 'booking_form_border_radius',
60 + 'booking_form_padding',
61 + 'booking_form_text_color',
62 + 'booking_form_field_background_color',
63 + 'booking_form_field_text_color',
64 + 'booking_form_field_border_color'
65 + ];
66 +
25 67 // -----------------------------------------------------------------------------------------------
26 68 // Small helpers
27 69 // -----------------------------------------------------------------------------------------------
28 70
@@ -64,11 +106,108 @@
64 106 return String(row.getAttribute('data-scope') || '') === String(scope);
65 107 });
66 108 }
67 109
68 - function has_any_rows() {
69 - return query_all(d, '.wpbc-setting[data-key]').length > 0;
70 - }
110 + function has_any_rows() {
111 + return query_all(d, '.wpbc-setting[data-key]').length > 0;
112 + }
113 +
114 + function init_coloris_pickers(root) {
115 + if ( ! root || ! w.Coloris ) {
116 + return;
117 + }
118 +
119 + const inputs = query_all(root, 'input[data-wpbc-bfb-fs-type="color"][data-coloris], input[data-inspector-type="color"][data-coloris]');
120 + if ( ! inputs.length ) {
121 + return;
122 + }
123 +
124 + inputs.forEach(function (input) {
125 + if (input.classList.contains('wpbc_bfb_coloris')) return;
126 + input.classList.add('wpbc_bfb_coloris');
127 + });
128 +
129 + try {
130 + w.Coloris({
131 + el : '.wpbc_bfb_coloris',
132 + alpha : false,
133 + format : 'hex',
134 + themeMode: 'auto',
135 + onChange : function (color, input) {
136 + if ( ! input ) {
137 + return;
138 + }
139 + try {
140 + input.dispatchEvent( new CustomEvent( 'wpbc:bfb:coloris:change', {
141 + bubbles: true,
142 + detail : {
143 + color : color,
144 + currentEl: input
145 + }
146 + } ) );
147 + } catch ( _e ) {}
148 + }
149 + });
150 + } catch (e) {
151 + console.warn('WPBC Form Settings: Coloris init failed:', e);
152 + }
153 + }
154 +
155 + function get_default_custom_appearance_settings() {
156 + const localized_custom_style = w.wpbc_bfb_settings_vars && w.wpbc_bfb_settings_vars.custom_form_style_defaults
157 + ? w.wpbc_bfb_settings_vars.custom_form_style_defaults
158 + : {};
159 + const localized_form_accent = w.wpbc_bfb_settings_vars && w.wpbc_bfb_settings_vars.form_accent_defaults
160 + ? w.wpbc_bfb_settings_vars.form_accent_defaults
161 + : {};
162 +
163 + return Object.assign( {
164 + booking_form_accent_enabled: 'Off',
165 + booking_form_custom_background_color : '#ffffff',
166 + booking_form_custom_border_color : '#cccccc',
167 + booking_form_custom_border_width : '1px',
168 + booking_form_custom_border_radius : '2px',
169 + booking_form_custom_padding_vertical : '10px',
170 + booking_form_custom_padding_horizontal : '30px',
171 + booking_form_custom_text_color : '#1d2327',
172 + booking_form_custom_field_background_color : '#ffffff',
173 + booking_form_custom_field_text_color : '#3c434a',
174 + booking_form_custom_field_border_color : '#cccccc',
175 + booking_form_custom_button_background_color: '#066aab',
176 + booking_form_custom_button_text_color : '#ffffff',
177 + booking_form_custom_button_border_color : '#066aab',
178 + booking_form_custom_button_hover_background_color: '#055589',
179 + booking_form_custom_button_hover_text_color: '#ffffff',
180 + booking_form_custom_button_hover_border_color: '#055589',
181 + booking_form_custom_secondary_button_background_color: '#fdfdfd',
182 + booking_form_custom_secondary_button_text_color: '#444444',
183 + booking_form_custom_secondary_button_border_color: '#eeeeee',
184 + booking_form_custom_secondary_button_hover_background_color: '#fdfdfd',
185 + booking_form_custom_secondary_button_hover_text_color: '#444444',
186 + booking_form_custom_secondary_button_hover_border_color: '#4d91cd',
187 + booking_form_custom_button_border_width : '1px',
188 + booking_form_custom_button_border_radius : '3px'
189 + }, localized_custom_style, localized_form_accent );
190 + }
191 +
192 + function get_form_style_option_keys() {
193 + const localized = w.wpbc_bfb_settings_vars && Array.isArray( w.wpbc_bfb_settings_vars.form_style_option_keys )
194 + ? w.wpbc_bfb_settings_vars.form_style_option_keys
195 + : [];
196 +
197 + return localized.length ? localized : fallback_form_style_option_keys;
198 + }
199 +
200 + function strip_form_style_options_from_pack(settings_pack) {
201 + if (!settings_pack || typeof settings_pack !== 'object') return settings_pack;
202 + if (!settings_pack.options || typeof settings_pack.options !== 'object') return settings_pack;
203 +
204 + get_form_style_option_keys().forEach(function (key) {
205 + delete settings_pack.options[key];
206 + });
207 +
208 + return settings_pack;
209 + }
71 210
72 211 // -----------------------------------------------------------------------------------------------
73 212 // Row setter
74 213 // -----------------------------------------------------------------------------------------------
@@ -90,14 +229,19 @@
90 229
91 230 const target_value = String(value == null ? '' : value);
92 231 const radios = query_all(row, 'input[type="radio"][name="' + css_escape(control_id) + '"]');
93 232
94 - let checked_radio = null;
95 - radios.forEach(function (radio) {
96 - const should_check = (String(radio.value) === target_value);
97 - radio.checked = should_check;
98 - if (should_check) checked_radio = radio;
99 - });
233 + let checked_radio = null;
234 + radios.forEach(function (radio) {
235 + const should_check = (String(radio.value) === target_value);
236 + radio.checked = should_check;
237 + if (should_check) checked_radio = radio;
238 +
239 + const choice = radio.closest ? radio.closest('.wpbc_theme_choice') : null;
240 + if ( choice ) {
241 + choice.classList.toggle('is-selected', should_check);
242 + }
243 + });
100 244
101 245 if (wrap) set_initial_attr(wrap, target_value);
102 246 if (do_trigger_events && checked_radio) trigger_change(checked_radio);
103 247 return;
@@ -133,10 +277,10 @@
133 277 if (do_trigger_events) trigger_change(select);
134 278 return;
135 279 }
136 280
137 - // Length: hidden combined + num/unit
138 - if ( row_type === 'length' ) {
281 + // Length: hidden combined + num/unit
282 + if ( row_type === 'length' ) {
139 283 // JS slider length control: - hidden writer carries FS markers and must receive input event so wpbc_slider_len_groups.js syncs UI.
140 284 const writer =
141 285 row.querySelector( 'input[data-wpbc_slider_len_writer][data-wpbc-bfb-fs-type="length"]' ) ||
142 286 row.querySelector( 'input[data-wpbc-bfb-fs-type="length"]' );
@@ -145,11 +289,35 @@
145 289 const combined = String( value == null ? '' : value );
146 290 writer.value = combined;
147 291 set_initial_attr( writer, combined );
148 292 if ( do_trigger_events ) trigger_input( writer );
149 - return;
150 - }
151 -
293 + return;
294 + }
295 +
296 + // Spacing: two number inputs saved into a hidden CSS shorthand writer.
297 + if ( row_type === 'spacing' ) {
298 + const group = row.querySelector( '.wpbc_spacing_group' );
299 + const vertical_input = group ? group.querySelector( 'input[data-wpbc_spacing_vertical]' ) : null;
300 + const horizontal_input = group ? group.querySelector( 'input[data-wpbc_spacing_horizontal]' ) : null;
301 + const writer = group ? group.querySelector( 'input[data-wpbc_spacing_writer]' ) : null;
302 + const parsed = parse_spacing_value( value );
303 +
304 + if ( ! writer ) {
305 + return;
306 + }
307 +
308 + if ( vertical_input ) {
309 + vertical_input.value = parsed.vertical;
310 + }
311 + if ( horizontal_input ) {
312 + horizontal_input.value = parsed.horizontal;
313 + }
314 + writer.value = parsed.combined;
315 + set_initial_attr( writer, parsed.combined );
316 + if ( do_trigger_events ) trigger_input( writer );
317 + return;
318 + }
319 +
152 320 // Range (slider number): writer is the number input.
153 321 if (row_type === 'range') {
154 322 const writer =
155 323 row.querySelector('input[data-wpbc_slider_range_writer]') ||
@@ -200,13 +368,45 @@
200 368 * Supports:
201 369 * - flat: { booking_form_layout_width: '100%', ... }
202 370 * - pack: { options: {...}, css_vars: {...} } (Option A)
203 371 */
204 - api.apply = function (settings_pack, scope, opts) {
205 - if (!settings_pack || typeof settings_pack !== 'object') return;
206 - if (!settings_pack.options || typeof settings_pack.options !== 'object') return; // strict Option A
207 - apply_flat_settings(settings_pack.options, scope || 'form', opts);
208 - };
372 + api.apply = function (settings_pack, scope, opts) {
373 + if (!settings_pack || typeof settings_pack !== 'object') return;
374 + if (!settings_pack.options || typeof settings_pack.options !== 'object') return; // strict Option A
375 + strip_form_style_options_from_pack(settings_pack);
376 + apply_flat_settings(settings_pack.options, scope || 'form', opts);
377 + };
378 +
379 + api.reset_custom_appearance = function () {
380 + const defaults = get_default_custom_appearance_settings();
381 +
382 + if ( ! last_settings_pack || typeof last_settings_pack !== 'object' ) {
383 + last_settings_pack = { options: {}, css_vars: {} };
384 + }
385 + if ( ! last_settings_pack.options || typeof last_settings_pack.options !== 'object' ) {
386 + last_settings_pack.options = {};
387 + }
388 + Object.keys( defaults ).forEach( function (key) {
389 + last_settings_pack.options[key] = defaults[key];
390 + } );
391 +
392 + apply_flat_settings( defaults, 'global', { trigger_change: true } );
393 + init_coloris_pickers( d );
394 +
395 + if ( w.WPBC_BFB_Settings_Effects && typeof w.WPBC_BFB_Settings_Effects.apply_all === 'function' ) {
396 + w.WPBC_BFB_Settings_Effects.apply_all( defaults, { source: 'reset-custom-appearance', options: defaults } );
397 + }
398 +
399 + try {
400 + d.dispatchEvent( new CustomEvent( 'wpbc:bfb:form_settings:changed', {
401 + bubbles: true,
402 + detail : {
403 + source : 'reset-custom-appearance',
404 + settings: { options: Object.assign( {}, defaults ) }
405 + }
406 + } ) );
407 + } catch ( _e ) {}
408 + };
209 409
210 410 /**
211 411 * Collect current values (flat object).
212 412 */
@@ -241,14 +441,19 @@
241 441 out[key] = select ? String(select.value) : '';
242 442 return;
243 443 }
244 444
245 - if (type === 'length') {
246 - const hidden = row.querySelector('input[data-wpbc-bfb-fs-type="length"]');
247 - out[key] = hidden ? String(hidden.value || '') : '';
248 - return;
249 - }
250 -
445 + if (type === 'length') {
446 + const hidden = row.querySelector('input[data-wpbc-bfb-fs-type="length"]');
447 + out[key] = hidden ? String(hidden.value || '') : '';
448 + return;
449 + }
450 +
451 + if (type === 'spacing') {
452 + out[key] = get_spacing_value(row);
453 + return;
454 + }
455 +
251 456 if (type === 'range') {
252 457 const writer =
253 458 row.querySelector('input[data-wpbc_slider_range_writer]') ||
254 459 row.querySelector('input[type="number"]') ||
@@ -259,13 +464,49 @@
259 464 const control = row.querySelector('input,textarea');
260 465 out[key] = control ? String(control.value || '') : '';
261 466 });
262 467
263 - return out;
264 - };
265 -
266 - /**
267 - * Re-apply last received settings (useful after DOM re-render).
468 + return out;
469 + };
470 +
471 + function parse_spacing_value(value) {
472 + const fallback = { vertical: '10', horizontal: '30', combined: '10px 30px' };
473 + const matches = String(value == null ? '' : value).match(/-?\d+(?:\.\d+)?/g) || [];
474 + let vertical = matches[0] != null ? String(matches[0]) : fallback.vertical;
475 + let horizontal = matches[1] != null ? String(matches[1]) : vertical;
476 +
477 + if (isNaN(Number(vertical))) {
478 + vertical = fallback.vertical;
479 + }
480 + if (isNaN(Number(horizontal))) {
481 + horizontal = fallback.horizontal;
482 + }
483 +
484 + return {
485 + vertical : vertical,
486 + horizontal: horizontal,
487 + combined : vertical + 'px ' + horizontal + 'px'
488 + };
489 + }
490 +
491 + function get_spacing_value(row) {
492 + const group = row ? row.querySelector('.wpbc_spacing_group') : null;
493 + const vertical_input = group ? group.querySelector('input[data-wpbc_spacing_vertical]') : null;
494 + const horizontal_input = group ? group.querySelector('input[data-wpbc_spacing_horizontal]') : null;
495 + const writer = group ? group.querySelector('input[data-wpbc_spacing_writer]') : null;
496 + const vertical = vertical_input ? String(vertical_input.value || '0') : '0';
497 + const horizontal = horizontal_input ? String(horizontal_input.value || vertical) : vertical;
498 + const combined = parse_spacing_value(vertical + 'px ' + horizontal + 'px').combined;
499 +
500 + if (writer) {
501 + writer.value = combined;
502 + }
503 +
504 + return combined;
505 + }
506 +
507 + /**
508 + * Re-apply last received settings (useful after DOM re-render).
268 509 */
269 510 api.reapply_last = function () {
270 511 if (!last_settings_pack) return;
271 512 api.apply(last_settings_pack, 'form', { trigger_change: true });
@@ -270,12 +511,14 @@
270 511 if (!last_settings_pack) return;
271 512 api.apply(last_settings_pack, 'form', { trigger_change: true });
272 513 };
273 514
274 - api.init = function () {
275 - // If apply event fired before init, try again now.
276 - if (last_settings_pack) schedule_apply_retry();
277 - };
515 + api.init = function () {
516 + init_coloris_pickers(d);
517 +
518 + // If apply event fired before init, try again now.
519 + if (last_settings_pack) schedule_apply_retry();
520 + };
278 521
279 522 // -----------------------------------------------------------------------------------------------
280 523 // DOM Events (AJAX layer)
281 524 // -----------------------------------------------------------------------------------------------
@@ -291,24 +534,207 @@
291 534 if (!target_pack.options || typeof target_pack.options !== 'object') {
292 535 target_pack.options = {};
293 536 }
294 537
295 - const collected = api.collect('form');
296 - Object.keys(collected).forEach(function (k) {
297 - target_pack.options[k] = collected[k];
298 - });
299 - });
538 + const collected = api.collect('form');
539 + Object.keys(collected).forEach(function (k) {
540 + target_pack.options[k] = collected[k];
541 + });
542 + strip_form_style_options_from_pack(target_pack);
543 + });
300 544
301 545 // Load: receive settings from AJAX and apply.
302 - d.addEventListener('wpbc:bfb:form_settings:apply', function (e) {
303 - const detail = (e && e.detail) ? e.detail : {};
546 + d.addEventListener('wpbc:bfb:form_settings:apply', function (e) {
547 + const detail = (e && e.detail) ? e.detail : {};
548 +
549 + last_settings_pack = detail.settings || null;
550 +
551 + retry_count = 0;
552 + schedule_apply_retry();
553 + });
554 +
555 + d.addEventListener( 'click', function (e) {
556 + const btn = e && e.target && e.target.closest ? e.target.closest( '[data-wpbc-bfb-reset-custom-appearance]' ) : null;
557 + if ( ! btn ) {
558 + return;
559 + }
560 +
561 + e.preventDefault();
562 + api.reset_custom_appearance();
563 + }, false );
564 +
565 + /**
566 + * Switch the global time-picker skin to the form-aware Automatic skin.
567 + *
568 + * The option is saved through the existing nonce-protected option saver.
569 + * Legacy skins are changed only by this explicit user action.
570 + *
571 + * @param {HTMLButtonElement} button Accent action button.
572 + * @returns {boolean} Whether an AJAX option save was started.
573 + */
574 + function switch_time_picker_to_automatic(button) {
575 + const automatic_skin = '/css/time_picker_skins/form_style.css';
576 + const current_skin = button ? String( button.getAttribute( 'data-wpbc-time-picker-skin-current' ) || '' ) : '';
577 + const automatic_url = button ? String( button.getAttribute( 'data-wpbc-time-picker-skin-url' ) || '' ) : '';
578 +
579 + if ( ! button || current_skin.slice( -automatic_skin.length ) === automatic_skin ) {
580 + return false;
581 + }
582 + if ( typeof w.wpbc_save_option_from_element !== 'function' ) {
583 + return false;
584 + }
585 +
586 + const time_api = w.WPBC_BFB_Core && w.WPBC_BFB_Core.Time ? w.WPBC_BFB_Core.Time : null;
587 + if ( automatic_url ) {
588 + previous_time_picker_skin_url = d.getElementById( 'wpbc-time_picker-skin-css' )
589 + ? String( d.getElementById( 'wpbc-time_picker-skin-css' ).getAttribute( 'href' ) || '' )
590 + : '';
591 + if ( time_api && typeof time_api.apply_picker_skin_url === 'function' ) {
592 + time_api.apply_picker_skin_url( automatic_url );
593 + } else if ( typeof w.wpbc__css__change_skin === 'function' && d.getElementById( 'wpbc-time_picker-skin-css' ) ) {
594 + w.wpbc__css__change_skin( automatic_url, 'wpbc-time_picker-skin-css' );
595 + }
596 + }
597 +
598 + pending_time_picker_skin_button = button;
599 + button.setAttribute( 'data-wpbc-u-save-value', automatic_skin );
600 + w.wpbc_save_option_from_element( button );
601 +
602 + return true;
603 + }
604 +
605 + /**
606 + * Mark the Automatic skin as current after the option saver confirms it.
607 + *
608 + * @returns {void}
609 + */
610 + w.wpbc_bfb_time_picker_skin_saved = function () {
611 + if ( pending_time_picker_skin_button ) {
612 + pending_time_picker_skin_button.setAttribute( 'data-wpbc-time-picker-skin-current', '/css/time_picker_skins/form_style.css' );
613 + }
614 + if ( w.WPBC_BFB_Core && w.WPBC_BFB_Core.Time && typeof w.WPBC_BFB_Core.Time.ui_set_picker_skin_value === 'function' ) {
615 + w.WPBC_BFB_Core.Time.ui_set_picker_skin_value( '/css/time_picker_skins/form_style.css' );
616 + }
617 + pending_time_picker_skin_button = null;
618 + previous_time_picker_skin_url = '';
619 + };
620 +
621 + if ( w.jQuery ) {
622 + w.jQuery( d ).on( 'wpbc:option:afterSave.wpbcBfbTimePickerSkin', function (event, response) {
623 + if ( ! pending_time_picker_skin_button || ( response && response.success ) ) {
624 + return;
625 + }
626 + const previous_skin = String( pending_time_picker_skin_button.getAttribute( 'data-wpbc-time-picker-skin-current' ) || '' );
627 +
628 + const time_api = w.WPBC_BFB_Core && w.WPBC_BFB_Core.Time ? w.WPBC_BFB_Core.Time : null;
629 + if ( previous_time_picker_skin_url && time_api && typeof time_api.apply_picker_skin_url === 'function' ) {
630 + time_api.apply_picker_skin_url( previous_time_picker_skin_url );
631 + } else if ( previous_time_picker_skin_url && typeof w.wpbc__css__change_skin === 'function' ) {
632 + w.wpbc__css__change_skin( previous_time_picker_skin_url, 'wpbc-time_picker-skin-css' );
633 + }
634 + if ( w.WPBC_BFB_Core && w.WPBC_BFB_Core.Time && typeof w.WPBC_BFB_Core.Time.ui_set_picker_skin_value === 'function' ) {
635 + w.WPBC_BFB_Core.Time.ui_set_picker_skin_value( previous_skin );
636 + }
637 + pending_time_picker_skin_button = null;
638 + previous_time_picker_skin_url = '';
639 + } );
640 + }
641 +
642 + /**
643 + * Ask accent-capable field packs to copy the current accent into their
644 + * existing editable color properties. Field packs update the counters.
645 + *
646 + * @param {HTMLButtonElement} button Action button.
647 + * @returns {void}
648 + */
649 + api.apply_accent_to_components = function (button) {
650 + const toggle = d.getElementById( 'booking_form_accent_enabled' );
651 + const color_control = d.getElementById( 'booking_form_accent_color' );
652 + const status = d.querySelector( '[data-wpbc-bfb-accent-components-status="1"]' );
653 + const i18n = w.wpbc_bfb_settings_vars && w.wpbc_bfb_settings_vars.i18n ? w.wpbc_bfb_settings_vars.i18n : {};
654 + const default_appearance = get_default_custom_appearance_settings();
655 + const accent_color = color_control && /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( String( color_control.value || '' ).trim() )
656 + ? String( color_control.value ).trim()
657 + : String( default_appearance.booking_form_accent_color || '' ).trim();
658 +
659 + if ( ! toggle || ! toggle.checked ) {
660 + if ( status ) {
661 + status.textContent = i18n.accent_enable_first || 'Enable Custom accent color first.';
662 + }
663 + return;
664 + }
665 +
666 + if ( button ) {
667 + button.disabled = true;
668 + }
669 +
670 + const apply_to_builder = function (builder) {
671 + const detail = {
672 + accent_color: accent_color,
673 + builder : builder || w.wpbc_bfb || null,
674 + matched : 0,
675 + updated : 0
676 + };
677 +
678 + try {
679 + d.dispatchEvent( new CustomEvent( 'wpbc:bfb:apply-accent-to-components', {
680 + bubbles: true,
681 + detail : detail
682 + } ) );
683 + } catch ( _e ) {}
684 +
685 + const time_picker_save_started = switch_time_picker_to_automatic( button );
686 +
687 + if ( status ) {
688 + if ( detail.updated > 0 ) {
689 + status.textContent = ( 1 === detail.updated )
690 + ? ( i18n.accent_applied_one || 'Accent applied to one form element. Save Form to keep the change.' )
691 + : String( i18n.accent_applied_many || 'Accent applied to %d form elements. Save Form to keep the changes.' ).replace( '%d', String( detail.updated ) );
692 + } else if ( detail.matched > 0 ) {
693 + status.textContent = i18n.accent_already_applied || 'All supported form elements already have the current accent color.';
694 + } else {
695 + status.textContent = i18n.accent_no_elements || 'No accent-capable form elements were found.';
696 + }
697 + if ( time_picker_save_started ) {
698 + status.textContent += ' ' + ( i18n.accent_time_picker_automatic || 'Time slots now use Automatic — Match Booking Form.' );
699 + }
700 + }
701 +
702 + if ( detail.updated > 0 ) {
703 + try {
704 + d.dispatchEvent( new CustomEvent( 'wpbc:bfb:structure:change', {
705 + bubbles: true,
706 + detail : { source: 'apply-accent-to-components', updated: detail.updated }
707 + } ) );
708 + } catch ( _e2 ) {}
709 + }
710 +
711 + if ( detail.builder && typeof detail.builder._announce === 'function' ) {
712 + detail.builder._announce( status ? status.textContent : ( i18n.accent_applied_announcement || 'Form accent applied.' ) );
713 + }
714 + if ( button && ! time_picker_save_started ) {
715 + button.disabled = false;
716 + }
717 + };
718 +
719 + if ( w.wpbc_bfb_api && w.wpbc_bfb_api.ready && typeof w.wpbc_bfb_api.ready.then === 'function' ) {
720 + w.wpbc_bfb_api.ready.then( apply_to_builder );
721 + return;
722 + }
723 +
724 + apply_to_builder( w.wpbc_bfb || null );
725 + };
726 +
727 + d.addEventListener( 'click', function (e) {
728 + const btn = e && e.target && e.target.closest ? e.target.closest( '[data-wpbc-bfb-apply-accent-components="1"]' ) : null;
729 + if ( ! btn ) {
730 + return;
731 + }
732 +
733 + e.preventDefault();
734 + api.apply_accent_to_components( btn );
735 + }, false );
304 736
305 - last_settings_pack = detail.settings || null;
306 -
307 - retry_count = 0;
308 - schedule_apply_retry();
309 - });
310 -
311 737 function schedule_apply_retry() {
312 738 if (raf_id) return;
313 739
314 740 raf_id = w.requestAnimationFrame(function () {
@@ -320,11 +746,12 @@
320 746 if (retry_count < retry_max) schedule_apply_retry();
321 747 return;
322 748 }
323 749
324 - api.reapply_last();
325 - });
326 - }
750 + api.reapply_last();
751 + init_coloris_pickers(d);
752 + });
753 + }
327 754
328 755 // -----------------------------------------------------------------------------------------------
329 756 // Optional Builder timing hook (STRUCTURE_LOADED) -> reapply_last()
330 757 // -----------------------------------------------------------------------------------------------