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
booking / includes / page-settings-themes / _src / settings_themes_page.js

settings_themes_page.js in Booking Calendar 11.9, at includes/page-settings-themes/_src/settings_themes_page.js

979 lines 36.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Appearance / Theme settings page UI.
3 */
4 ( function ( $, w ) {
5 'use strict';
6
7 var cfg = w.wpbc_settings_themes_page || {};
8 var localized_default_form_accent_color = String( cfg.form_accent_defaults && cfg.form_accent_defaults.booking_form_accent_color || '' ).trim();
9
10 /** @type {string} Default accent supplied by the PHP configuration constant. */
11 var default_form_accent_color = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( localized_default_form_accent_color )
12 ? localized_default_form_accent_color
13 : '';
14 var preview_ajax = null;
15 var preview_timer = 0;
16 var preview_notice_timer = 0;
17 var preview_notice_message_timer = 0;
18
19 function trim_text( value ) {
20 return String( value || '' ).trim();
21 }
22
23 function make_asset_url( path ) {
24 path = String( path || '' );
25 if ( /^https?:\/\//i.test( path ) || /^\/\//.test( path ) ) {
26 return path;
27 }
28 return String( cfg.plugin_url || '' ).replace( /\/$/, '' ) + path;
29 }
30
31 function show_message( message, type, delay ) {
32 if ( typeof w.wpbc_admin_show_message === 'function' ) {
33 w.wpbc_admin_show_message( message, type || 'info', delay || 4000, false );
34 }
35 }
36
37 function pulse_element( $element, duration ) {
38 if ( ! $element || ! $element.length ) {
39 return;
40 }
41
42 $element
43 .removeClass( 'wpbc_theme_attention_pulse' )
44 .each( function () {
45 void this.offsetWidth;
46 } )
47 .addClass( 'wpbc_theme_attention_pulse' );
48
49 setTimeout( function () {
50 $element.removeClass( 'wpbc_theme_attention_pulse' );
51 }, duration || 2100 );
52 }
53
54 function pulse_latest_warning_notice() {
55 clearTimeout( preview_notice_message_timer );
56 preview_notice_message_timer = setTimeout( function () {
57 pulse_element( $( '#ajax_working .wpbc_inner_message.notice-warning' ).last() );
58 }, 50 );
59 }
60
61 function show_highlighted_notice( message, type, delay, $control ) {
62 if ( $control && $control.length ) {
63 pulse_element( $control );
64 }
65
66 show_message( message, type || 'warning', delay || 9000 );
67 pulse_latest_warning_notice();
68 }
69
70 function switch_panel( $tab ) {
71 var panel_id = $tab.attr( 'aria-controls' );
72 var $tabs = $tab.closest( '.wpbc_theme_rightbar_tabs' ).find( '[role="tab"]' );
73 var $panels = $( '.wpbc_theme_rightbar_panels [role="tabpanel"]' );
74
75 $tabs.attr( 'aria-selected', 'false' );
76 $tab.attr( 'aria-selected', 'true' );
77
78 $panels.attr( 'hidden', 'hidden' ).attr( 'aria-hidden', 'true' );
79 $( '#' + panel_id ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
80 }
81
82 function toggle_group( $button ) {
83 var $group = $button.closest( '.wpbc_ui__collapsible_group' );
84 var $fields = $group.find( '> .group__fields' );
85 var is_open = $group.hasClass( 'is-open' );
86
87 $group.toggleClass( 'is-open', ! is_open );
88 $button.attr( 'aria-expanded', is_open ? 'false' : 'true' );
89 $fields.prop( 'hidden', is_open ).attr( 'aria-hidden', is_open ? 'true' : 'false' );
90 }
91
92 function get_form() {
93 return $( '[data-wpbc-theme-settings-form="1"]' ).first();
94 }
95
96 function collect_payload() {
97 var $form = get_form();
98 var data = {};
99
100 sync_form_style_choice();
101
102 $.each( $form.serializeArray(), function ( index, item ) {
103 if ( 0 === String( item.name || '' ).indexOf( 'wpbc_setup' ) ) {
104 return;
105 }
106 data[ item.name ] = item.value;
107 } );
108
109 data.booking_timeslot_picker = $form.find( '[name="booking_timeslot_picker"]' ).prop( 'checked' ) ? 'On' : 'Off';
110 data.booking_form_accent_enabled = $form.find( '[name="booking_form_accent_enabled"]' ).prop( 'checked' ) ? 'On' : 'Off';
111 data.resource_id = $( '#wpbc_theme_resource_id' ).val() || '';
112 data.months_count = $( '#wpbc_theme_months_count' ).val() || '';
113 data.preview_mode = $( '#wpbc_theme_preview_mode' ).val() || 'form';
114 data.custom_booking_form = $( '#wpbc_theme_custom_form' ).val() || 'standard';
115
116 return data;
117 }
118
119 function map_form_style_choice( value ) {
120 var choice = String( value || 'light_bordered' );
121 var current_theme = $( '#booking_form_theme' ).val() || '';
122 var parts;
123 var preset;
124
125 if ( 'custom' === choice ) {
126 return {
127 theme : current_theme,
128 preset: 'custom'
129 };
130 }
131
132 parts = choice.split( '_' );
133 preset = parts[1] || 'bordered';
134 if ( [ 'bordered', 'none', 'soft' ].indexOf( preset ) === -1 ) {
135 preset = 'bordered';
136 }
137
138 return {
139 theme : ( 'dark' === parts[0] ) ? 'wpbc_theme_dark_1' : '',
140 preset: preset
141 };
142 }
143
144 function get_form_style_choice_from_values() {
145 var theme = $( '#booking_form_theme' ).val() || '';
146 var preset = $( '#booking_form_appearance_preset' ).val() || 'bordered';
147 var prefix = theme ? 'dark' : 'light';
148
149 if ( 'custom' === preset ) {
150 return 'custom';
151 }
152 if ( [ 'bordered', 'none', 'soft' ].indexOf( preset ) === -1 ) {
153 preset = 'bordered';
154 }
155
156 return prefix + '_' + preset;
157 }
158
159 function sync_form_style_choice() {
160 var $checked = get_form().find( '[name="booking_form_style"]:checked' );
161 var mapped;
162
163 if ( ! $checked.length ) {
164 return;
165 }
166
167 mapped = map_form_style_choice( $checked.val() );
168 $( '#booking_form_theme' ).val( mapped.theme );
169 $( '#booking_form_appearance_preset' ).val( mapped.preset );
170 }
171
172 function sync_form_style_choice_selection() {
173 var choice = get_form_style_choice_from_values();
174 var $choices = get_form().find( '[name="booking_form_style"]' );
175
176 $choices.prop( 'checked', false );
177 $choices.filter( '[value="' + choice + '"]' ).prop( 'checked', true );
178
179 $( '.wpbc_theme_choice' ).removeClass( 'is-selected' );
180 $choices.filter( ':checked' ).closest( '.wpbc_theme_choice' ).addClass( 'is-selected' );
181 }
182
183 function apply_form_theme() {
184 var theme = $( '#booking_form_theme' ).val() || '';
185 var $preview = $( '[data-wpbc-theme-preview="1"]' );
186 var $theme_targets = $preview.add( $preview.find( '.wpbc_container.wpbc_form, .wpbc_container_booking_form' ) );
187
188 $theme_targets.each( function () {
189 var $target = $( this );
190 var classes = String( this.className || '' ).split( /\s+/ );
191
192 $.each( classes, function ( index, class_name ) {
193 if ( /^wpbc_theme_/.test( class_name ) && ! /^wpbc_theme_preview/.test( class_name ) ) {
194 $target.removeClass( class_name );
195 }
196 } );
197 } );
198 if ( theme ) {
199 $theme_targets.addClass( theme );
200 }
201
202 sync_form_style_choice_selection();
203 }
204
205 function get_form_appearance_presets() {
206 return {
207 bordered: {
208 background : '#ffffff',
209 borderColor: '#cccccc',
210 borderWidth: '1px',
211 radius : '2px',
212 padding : '10px 30px',
213 shadow : 'rgba(0, 0, 0, 0.05) 0px 2px 6px 0px'
214 },
215 none : {
216 background : 'transparent',
217 borderColor: 'transparent',
218 borderWidth: '0px',
219 radius : '0px',
220 padding : '0px',
221 shadow : 'none'
222 },
223 soft : {
224 background : '#f9f9fa',
225 borderColor: '#fff',
226 borderWidth: '3px',
227 radius : '8px',
228 padding : '20px',
229 shadow : 'rgba(15, 23, 42, 0.06) 0px 4px 16px 0px'
230 }
231 };
232 }
233
234 function is_dark_form_theme() {
235 return 'wpbc_theme_dark_1' === String( $( '#booking_form_theme' ).val() || '' );
236 }
237
238 function get_form_appearance_preset_for_theme( preset ) {
239 var presets = get_form_appearance_presets();
240
241 if ( ! is_dark_form_theme() ) {
242 return presets[preset] || presets.bordered;
243 }
244
245 if ( 'soft' === preset ) {
246 return {
247 background : '#1f2937',
248 borderColor: '#334155',
249 borderWidth: '3px',
250 radius : '8px',
251 padding : '20px',
252 shadow : 'rgba(0, 0, 0, 0.24) 0px 4px 16px 0px'
253 };
254 }
255
256 return presets[preset] || presets.bordered;
257 }
258
259 function sanitize_theme_color( value, fallback ) {
260 var v = String( value || '' ).trim();
261 return /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( v ) || 'transparent' === v ? v : fallback;
262 }
263
264 function sanitize_theme_length( value, fallback ) {
265 var v = String( value || '' ).trim();
266 return /^\d+(?:\.\d+)?(?:px|rem|em|%)$/i.test( v ) ? v : fallback;
267 }
268
269 function sanitize_theme_spacing( value, fallback ) {
270 var v = String( value || '' ).trim().replace( /\s+/g, ' ' );
271 var parts = v ? v.split( ' ' ) : [];
272 var i;
273
274 if ( parts.length < 1 || parts.length > 4 ) {
275 return fallback;
276 }
277 for ( i = 0; i < parts.length; i++ ) {
278 if ( ! /^\d+(?:\.\d+)?(?:px|rem|em|%)$/i.test( parts[i] ) ) {
279 return fallback;
280 }
281 }
282 return parts.join( ' ' );
283 }
284
285 function mix_theme_colors( color, target, amount ) {
286 var source = sanitize_theme_color( color, default_form_accent_color ).replace( '#', '' );
287 var destination = sanitize_theme_color( target, '#000000' ).replace( '#', '' );
288 var channels = [];
289 var index;
290
291 if ( 3 === source.length ) {
292 source = source.replace( /./g, function ( value ) { return value + value; } );
293 }
294 for ( index = 0; index < 3; index++ ) {
295 channels.push( Math.round( parseInt( source.substr( index * 2, 2 ), 16 ) + ( ( parseInt( destination.substr( index * 2, 2 ), 16 ) - parseInt( source.substr( index * 2, 2 ), 16 ) ) * amount ) ) );
296 }
297
298 return '#' + channels.map( function ( channel ) { return ( '0' + channel.toString( 16 ) ).slice( -2 ); } ).join( '' );
299 }
300
301 function get_theme_color_luminance( color ) {
302 var hex = sanitize_theme_color( color, default_form_accent_color ).replace( '#', '' );
303 var channels;
304 if ( 3 === hex.length ) {
305 hex = hex.replace( /./g, function ( value ) { return value + value; } );
306 }
307 channels = [ 0, 1, 2 ].map( function ( index ) {
308 var channel = parseInt( hex.substr( index * 2, 2 ), 16 ) / 255;
309 return channel <= 0.03928 ? channel / 12.92 : Math.pow( ( channel + 0.055 ) / 1.055, 2.4 );
310 } );
311 return ( 0.2126 * channels[0] ) + ( 0.7152 * channels[1] ) + ( 0.0722 * channels[2] );
312 }
313
314 /**
315 * Apply the accent to preview variables while respecting Custom button controls.
316 *
317 * @param {Object} css_vars Resolved preview variables.
318 * @param {boolean} preserve_custom_button_colors Whether Custom button variables remain authoritative.
319 * @return {Object} Preview variables with the optional accent overlay.
320 */
321 function apply_form_accent_css_vars( css_vars, preserve_custom_button_colors ) {
322 var enabled = get_form().find( '[name="booking_form_accent_enabled"]' ).prop( 'checked' );
323 var accent_raw = String( get_form().find( '[name="booking_form_accent_color"]' ).val() || '' ).trim();
324 var accent = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( accent_raw ) ? accent_raw : default_form_accent_color;
325 var luminance;
326 var hover;
327 var contrast;
328 var hover_contrast;
329
330 if ( ! enabled ) {
331 return css_vars;
332 }
333 if ( ! /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test( accent ) ) {
334 return css_vars;
335 }
336 luminance = get_theme_color_luminance( accent );
337 contrast = luminance > 0.18 ? '#000000' : '#ffffff';
338 hover = mix_theme_colors( accent, '#ffffff' === contrast ? '#000000' : '#ffffff', 0.10 );
339 hover_contrast = contrast;
340
341 var accent_overlay = {
342 '--wpbc_form-accent-color': accent,
343 '--wpbc_form-accent-hover-color': hover,
344 '--wpbc_form-accent-contrast-color': contrast,
345 '--wpbc_form-field-focus-border-color': accent,
346 '--wpbc_form-field-focus-shadow-color': accent,
347 '--wpbc_form-choice-checked-border-color': accent,
348 '--wpbc_form-choice-checked-color': accent,
349 '--wpbc_form-choice-focus-color': accent,
350 '--wpbc_form-button-background-color': accent,
351 '--wpbc_form-button-background-color-alt': accent,
352 '--wpbc_form-button-border-color': accent,
353 '--wpbc_form-button-text-color': contrast,
354 '--wpbc_form-button-text-color-alt': contrast,
355 '--wpbc_form-button-hover-background-color': hover,
356 '--wpbc_form-button-hover-border-color': hover,
357 '--wpbc_form-button-hover-text-color': hover_contrast,
358 '--wpbc_form-button-light-hover-border-color': accent,
359 '--wpbc_form-button-primary-hover-border-color': hover,
360 '--wpbc_form-page-break-color': accent
361 };
362
363 if ( preserve_custom_button_colors ) {
364 [
365 '--wpbc_form-button-background-color',
366 '--wpbc_form-button-background-color-alt',
367 '--wpbc_form-button-border-color',
368 '--wpbc_form-button-text-color',
369 '--wpbc_form-button-text-color-alt',
370 '--wpbc_form-button-hover-background-color',
371 '--wpbc_form-button-hover-border-color',
372 '--wpbc_form-button-hover-text-color',
373 '--wpbc_form-button-light-hover-border-color',
374 '--wpbc_form-button-primary-hover-border-color'
375 ].forEach( function ( css_var_name ) {
376 delete accent_overlay[ css_var_name ];
377 } );
378 }
379
380 return $.extend( {}, css_vars, accent_overlay );
381 }
382
383 function get_form_style_presets() {
384 return cfg.form_style_presets && 'object' === typeof cfg.form_style_presets ? cfg.form_style_presets : {};
385 }
386
387 function get_current_form_style() {
388 var $checked = get_form().find( '[name="booking_form_style"]:checked' );
389 return $checked.length ? String( $checked.val() || 'light_bordered' ) : 'light_bordered';
390 }
391
392 function get_custom_form_style_defaults() {
393 return $.extend( {
394 booking_form_custom_background_color : '#ffffff',
395 booking_form_custom_border_color : '#cccccc',
396 booking_form_custom_border_width : '1px',
397 booking_form_custom_border_radius : '2px',
398 booking_form_custom_padding_vertical : '10px',
399 booking_form_custom_padding_horizontal : '30px',
400 booking_form_custom_text_color : '#1d2327',
401 booking_form_custom_field_background_color : '#ffffff',
402 booking_form_custom_field_text_color : '#3c434a',
403 booking_form_custom_field_border_color : '#cccccc',
404 booking_form_custom_button_background_color: '#066aab',
405 booking_form_custom_button_text_color : '#ffffff',
406 booking_form_custom_button_border_color : '#066aab',
407 booking_form_custom_button_hover_background_color: '#055589',
408 booking_form_custom_button_hover_text_color: '#ffffff',
409 booking_form_custom_button_hover_border_color: '#055589',
410 booking_form_custom_secondary_button_background_color: '#fdfdfd',
411 booking_form_custom_secondary_button_text_color: '#444444',
412 booking_form_custom_secondary_button_border_color: '#eeeeee',
413 booking_form_custom_secondary_button_hover_background_color: '#fdfdfd',
414 booking_form_custom_secondary_button_hover_text_color: '#444444',
415 booking_form_custom_secondary_button_hover_border_color: '#4d91cd',
416 booking_form_custom_button_border_width: '1px',
417 booking_form_custom_button_border_radius: '3px'
418 }, cfg.custom_form_style_defaults && 'object' === typeof cfg.custom_form_style_defaults ? cfg.custom_form_style_defaults : {} );
419 }
420
421 function get_custom_form_style_css_vars() {
422 var defaults = get_custom_form_style_defaults();
423 var values = $.extend( {}, defaults, cfg.settings && 'object' === typeof cfg.settings ? cfg.settings : {} );
424
425 return {
426 '--wpbc-bfb-form-background' : sanitize_theme_color( values.booking_form_custom_background_color, defaults.booking_form_custom_background_color ),
427 '--wpbc-bfb-form-border-color' : sanitize_theme_color( values.booking_form_custom_border_color, defaults.booking_form_custom_border_color ),
428 '--wpbc-bfb-form-border-width' : sanitize_theme_length( values.booking_form_custom_border_width, defaults.booking_form_custom_border_width ),
429 '--wpbc-bfb-form-border-radius' : sanitize_theme_length( values.booking_form_custom_border_radius, defaults.booking_form_custom_border_radius ),
430 '--wpbc-bfb-form-padding' : sanitize_theme_length( values.booking_form_custom_padding_vertical, defaults.booking_form_custom_padding_vertical ) + ' ' + sanitize_theme_length( values.booking_form_custom_padding_horizontal, defaults.booking_form_custom_padding_horizontal ),
431 '--wpbc-bfb-form-box-shadow' : 'rgba(0, 0, 0, 0.05) 0px 2px 6px 0px',
432 '--wpbc_form-label-color' : sanitize_theme_color( values.booking_form_custom_text_color, defaults.booking_form_custom_text_color ),
433 '--wpbc_form-label-sublabel-color' : sanitize_theme_color( values.booking_form_custom_text_color, defaults.booking_form_custom_text_color ),
434 '--wpbc_form-label-error-color' : '#d63637',
435 '--wpbc_form-field-background-color' : sanitize_theme_color( values.booking_form_custom_field_background_color, defaults.booking_form_custom_field_background_color ),
436 '--wpbc_form-field-menu-color' : sanitize_theme_color( values.booking_form_custom_field_background_color, defaults.booking_form_custom_field_background_color ),
437 '--wpbc_form-field-text-color' : sanitize_theme_color( values.booking_form_custom_field_text_color, defaults.booking_form_custom_field_text_color ),
438 '--wpbc_form-field-border-color' : sanitize_theme_color( values.booking_form_custom_field_border_color, defaults.booking_form_custom_field_border_color ),
439 '--wpbc_form-field-border-color-spare': sanitize_theme_color( values.booking_form_custom_field_border_color, defaults.booking_form_custom_field_border_color ),
440 '--wpbc_form-field-focus-border-color': '#066aab',
441 '--wpbc_form-field-focus-shadow-color': '#066aab',
442 '--wpbc_form-field-disabled-color' : 'rgba(0, 0, 0, 0.2)',
443 '--wpbc_form-button-border-radius' : sanitize_theme_length( values.booking_form_custom_button_border_radius, defaults.booking_form_custom_button_border_radius ),
444 '--wpbc_form-button-border-style' : 'solid',
445 '--wpbc_form-button-border-size' : sanitize_theme_length( values.booking_form_custom_button_border_width, defaults.booking_form_custom_button_border_width ),
446 '--wpbc_form-button-background-color' : sanitize_theme_color( values.booking_form_custom_button_background_color, defaults.booking_form_custom_button_background_color ),
447 '--wpbc_form-button-background-color-alt': sanitize_theme_color( values.booking_form_custom_button_background_color, defaults.booking_form_custom_button_background_color ),
448 '--wpbc_form-button-border-color' : sanitize_theme_color( values.booking_form_custom_button_border_color, defaults.booking_form_custom_button_border_color ),
449 '--wpbc_form-button-text-color' : sanitize_theme_color( values.booking_form_custom_button_text_color, defaults.booking_form_custom_button_text_color ),
450 '--wpbc_form-button-text-color-alt' : sanitize_theme_color( values.booking_form_custom_button_text_color, defaults.booking_form_custom_button_text_color ),
451 '--wpbc_form-button-hover-background-color': sanitize_theme_color( values.booking_form_custom_button_hover_background_color, defaults.booking_form_custom_button_hover_background_color ),
452 '--wpbc_form-button-hover-border-color': sanitize_theme_color( values.booking_form_custom_button_hover_border_color, defaults.booking_form_custom_button_hover_border_color ),
453 '--wpbc_form-button-hover-text-color' : sanitize_theme_color( values.booking_form_custom_button_hover_text_color, defaults.booking_form_custom_button_hover_text_color ),
454 '--wpbc_form-choice-checked-border-color': '#066aab',
455 '--wpbc_form-choice-checked-color' : '#066aab',
456 '--wpbc_form-choice-focus-color' : '#066aab',
457 '--wpbc_form-button-light-background-color': sanitize_theme_color( values.booking_form_custom_secondary_button_background_color, defaults.booking_form_custom_secondary_button_background_color ),
458 '--wpbc_form-button-light-border-color': sanitize_theme_color( values.booking_form_custom_secondary_button_border_color, defaults.booking_form_custom_secondary_button_border_color ),
459 '--wpbc_form-button-light-border-size': sanitize_theme_length( values.booking_form_custom_button_border_width, defaults.booking_form_custom_button_border_width ),
460 '--wpbc_form-button-light-text-color' : sanitize_theme_color( values.booking_form_custom_secondary_button_text_color, defaults.booking_form_custom_secondary_button_text_color ),
461 '--wpbc_form-button-light-box-shadow' : '0 2px 10px 2px #ffffff54',
462 '--wpbc_form-button-light-hover-background-color': sanitize_theme_color( values.booking_form_custom_secondary_button_hover_background_color, defaults.booking_form_custom_secondary_button_hover_background_color ),
463 '--wpbc_form-button-light-hover-border-color': sanitize_theme_color( values.booking_form_custom_secondary_button_hover_border_color, defaults.booking_form_custom_secondary_button_hover_border_color ),
464 '--wpbc_form-button-light-hover-text-color': sanitize_theme_color( values.booking_form_custom_secondary_button_hover_text_color, defaults.booking_form_custom_secondary_button_hover_text_color ),
465 '--wpbc_form-button-light-hover-box-shadow': '0 2px 10px 2px #ffffff54',
466 '--wpbc_form-button-primary-hover-border-color': sanitize_theme_color( values.booking_form_custom_button_hover_border_color, defaults.booking_form_custom_button_hover_border_color ),
467 '--wpbc_form-page-break-color' : '#066aab'
468 };
469 }
470
471 function get_form_style_css_var_names() {
472 var keys = [];
473 var presets;
474
475 if ( Array.isArray( cfg.form_style_css_var_names ) && cfg.form_style_css_var_names.length ) {
476 return cfg.form_style_css_var_names;
477 }
478
479 presets = get_form_style_presets();
480 $.each( presets, function ( preset_key, preset ) {
481 if ( preset && preset.css_vars && 'object' === typeof preset.css_vars ) {
482 $.each( preset.css_vars, function ( var_name ) {
483 if ( -1 === keys.indexOf( var_name ) ) {
484 keys.push( var_name );
485 }
486 } );
487 }
488 } );
489
490 $.each( get_custom_form_style_css_vars(), function ( var_name ) {
491 if ( -1 === keys.indexOf( var_name ) ) {
492 keys.push( var_name );
493 }
494 } );
495
496 return keys;
497 }
498
499 function resolve_form_style_css_vars( style ) {
500 var presets = get_form_style_presets();
501 var preset = presets[ style ] || presets.light_bordered || {};
502
503 if ( 'custom' === style || preset.custom ) {
504 return apply_form_accent_css_vars( get_custom_form_style_css_vars(), true );
505 }
506
507 return apply_form_accent_css_vars( preset.css_vars && 'object' === typeof preset.css_vars ? preset.css_vars : {} );
508 }
509
510 function apply_form_style_to_preview() {
511 var style = get_current_form_style();
512 var presets = get_form_style_presets();
513 var preset = presets[ style ] || presets.light_bordered || {};
514 var css_vars = resolve_form_style_css_vars( style );
515 var css_var_names = get_form_style_css_var_names();
516 var is_custom = ( 'custom' === style || preset.custom );
517 var $preview = $( '[data-wpbc-theme-preview="1"]' );
518 var $targets = $preview.find( '.wpbc_container.wpbc_form, .wpbc_bfb_form, .wpbc_bfb__form_preview_section_container' );
519
520 $( '[data-wpbc-theme-custom-appearance-notice="1"]' ).toggle( is_custom );
521
522 if ( ! $targets.length ) {
523 return;
524 }
525
526 $targets
527 .removeClass( 'wpbc_bfb_form_appearance_custom' )
528 .each( function () {
529 var style_obj = this.style;
530
531 $.each( css_var_names, function ( index, var_name ) {
532 style_obj.removeProperty( var_name );
533 } );
534
535 $.each( css_vars, function ( var_name, value ) {
536 if ( '' !== String( value || '' ) ) {
537 style_obj.setProperty( var_name, value );
538 }
539 } );
540 } );
541
542 if ( is_custom ) {
543 $targets.filter( '.wpbc_container.wpbc_form, .wpbc_bfb_form' ).addClass( 'wpbc_bfb_form_appearance_custom' );
544 }
545 }
546
547 function resolve_form_appearance() {
548 var preset = $( '#booking_form_appearance_preset' ).val() || 'bordered';
549
550 if ( 'custom' === preset ) {
551 return get_form_appearance_presets().bordered;
552 }
553
554 return get_form_appearance_preset_for_theme( preset );
555 }
556
557 function apply_form_appearance() {
558 apply_form_style_to_preview();
559 }
560
561 function apply_calendar_skin() {
562 var $select = $( '[data-wpbc-theme-calendar-skin="1"]' );
563 var value = $select.find( 'option:selected' ).attr( 'data-wpbc-calendar-skin-url' ) || $select.val() || '';
564 var skin_url = value ? make_asset_url( value ) : '';
565
566 if ( skin_url && typeof w.wpbc__calendar__change_skin === 'function' && $( '#wpbc-calendar-skin-css' ).length ) {
567 w.wpbc__calendar__change_skin( skin_url );
568 }
569 }
570
571 function apply_time_skin() {
572 var value = $( '[data-wpbc-theme-time-skin="1"]' ).val() || '';
573 var skin_url = value ? make_asset_url( value ) : '';
574
575 if ( skin_url && typeof w.wpbc__css__change_skin === 'function' && $( '#wpbc-time_picker-skin-css' ).length ) {
576 w.wpbc__css__change_skin( skin_url, 'wpbc-time_picker-skin-css' );
577 }
578 }
579
580 function select_if_option_exists( $select, value ) {
581 var $option;
582
583 if ( ! $select.length || ! value ) {
584 return false;
585 }
586
587 $option = $select.find( 'option[value="' + value + '"]' );
588 if ( ! $option.length ) {
589 return false;
590 }
591
592 if ( $select.val() === value ) {
593 return false;
594 }
595
596 $select.val( value ).trigger( 'change' );
597 return true;
598 }
599
600 function parse_number_list( value ) {
601 if ( Array.isArray( value ) ) {
602 return $.map( value, function ( item ) {
603 var parsed = parseInt( item, 10 );
604 return isNaN( parsed ) ? null : parsed;
605 } );
606 }
607
608 return $.map( String( value || '' ).split( /\s*,\s*/ ), function ( item ) {
609 var parsed = parseInt( item, 10 );
610 return ( '' === item || isNaN( parsed ) ) ? null : parsed;
611 } );
612 }
613
614 function set_calendar_param( resource_id, key, value ) {
615 if ( w._wpbc && typeof w._wpbc.calendar__set_param_value === 'function' ) {
616 w._wpbc.calendar__set_param_value( resource_id, key, value );
617 }
618 }
619
620 function apply_days_selection_to_calendar( resource_id, days_selection, should_reinit ) {
621 var ds = days_selection || {};
622 var fixed_week_days;
623 var dynamic_specific;
624 var dynamic_week_days;
625
626 if ( ! resource_id || ! w._wpbc || typeof w._wpbc.calendar__set_param_value !== 'function' ) {
627 return;
628 }
629
630 fixed_week_days = parse_number_list( ds.fixed__week_days__start );
631 dynamic_specific = parse_number_list( ds.dynamic__days_specific );
632 dynamic_week_days = parse_number_list( ds.dynamic__week_days__start );
633
634 set_calendar_param( resource_id, 'days_select_mode', String( ds.days_select_mode || 'multiple' ) );
635 set_calendar_param( resource_id, 'fixed__days_num', parseInt( ds.fixed__days_num || 0, 10 ) );
636 set_calendar_param( resource_id, 'fixed__week_days__start', fixed_week_days.length ? fixed_week_days : [ -1 ] );
637 set_calendar_param( resource_id, 'dynamic__days_min', parseInt( ds.dynamic__days_min || 0, 10 ) );
638 set_calendar_param( resource_id, 'dynamic__days_max', parseInt( ds.dynamic__days_max || 0, 10 ) );
639 set_calendar_param( resource_id, 'dynamic__days_specific', dynamic_specific );
640 set_calendar_param( resource_id, 'dynamic__week_days__start', dynamic_week_days.length ? dynamic_week_days : [ -1 ] );
641
642 if ( typeof w.wpbc__conditions__SAVE_INITIAL__days_selection_params__bm === 'function' ) {
643 w.wpbc__conditions__SAVE_INITIAL__days_selection_params__bm( resource_id );
644 }
645
646 if ( should_reinit && typeof w.wpbc_cal__re_init === 'function' ) {
647 w.wpbc_cal__re_init( resource_id );
648 }
649 }
650
651 function ensure_calendar_only_days_selection() {
652 var $preview = $( '[data-wpbc-theme-preview="1"]' ).first();
653 var preview_mode = $preview.attr( 'data-preview-mode' ) || $( '#wpbc_theme_preview_mode' ).val() || 'form';
654 var resource_id = parseInt( $preview.attr( 'data-resource-id' ) || 0, 10 );
655 var expected = cfg.days_selection || {};
656 var expected_mode = String( expected.days_select_mode || 'multiple' );
657 var current_mode = null;
658 var $calendar;
659 var should_reinit = false;
660
661 if ( 'calendar' !== preview_mode || ! resource_id || ! expected_mode ) {
662 return;
663 }
664
665 if ( ! w._wpbc || typeof w._wpbc.calendar__get_param_value !== 'function' ) {
666 return;
667 }
668
669 current_mode = w._wpbc.calendar__get_param_value( resource_id, 'days_select_mode' );
670 if ( String( current_mode || '' ) === expected_mode ) {
671 return;
672 }
673
674 $calendar = $( '#calendar_booking' + resource_id );
675 should_reinit = $calendar.length && $calendar.hasClass( 'hasDatepick' );
676
677 apply_days_selection_to_calendar( resource_id, expected, should_reinit );
678 }
679
680 function apply_related_skins_for_theme( theme ) {
681 var calendar_skin = theme ? '/css/skins/24_9__dark_1.css' : '/css/skins/25_5__square_1.css';
682 var time_skin = '/css/time_picker_skins/form_style.css';
683
684 select_if_option_exists( $( '[data-wpbc-theme-calendar-skin="1"]' ), calendar_skin );
685 select_if_option_exists( $( '[data-wpbc-theme-time-skin="1"]' ), time_skin );
686 }
687
688 function pulse_preview_mode_control() {
689 var $control = $( '.wpbc_theme_control_preview_mode' ).first();
690
691 pulse_element( $control );
692
693 clearTimeout( preview_notice_timer );
694 preview_notice_timer = setTimeout( function () {
695 $control.removeClass( 'wpbc_theme_attention_pulse' );
696 }, 2100 );
697 }
698
699 function get_preview_notice_message( notice_type ) {
700 var i18n = cfg.i18n || {};
701
702 if ( 'form' === notice_type ) {
703 return i18n.form_preview_option_notice || 'This option is visible in the Booking form preview. Switch Preview to Booking form to inspect it.';
704 }
705
706 return '';
707 }
708
709 function maybe_show_preview_notice( $source ) {
710 var notice_type = $source.attr( 'data-wpbc-theme-preview-notice' ) || '';
711 var preview_mode = $( '#wpbc_theme_preview_mode' ).val() || 'form';
712 var message = get_preview_notice_message( notice_type );
713 var $control = $( '.wpbc_theme_control_preview_mode' ).first();
714
715 if ( ! message ) {
716 return;
717 }
718
719 if ( 'form' === notice_type && 'calendar' !== preview_mode ) {
720 return;
721 }
722
723 if ( 'form' === notice_type ) {
724 pulse_preview_mode_control();
725 show_highlighted_notice( message, 'warning', 9000 );
726 return;
727 }
728
729 show_highlighted_notice( message, 'warning', 9000, $control );
730 }
731
732 function show_calendar_only_theme_notice() {
733 var preview_mode = $( '#wpbc_theme_preview_mode' ).val() || 'form';
734
735 if ( 'calendar' !== preview_mode ) {
736 return;
737 }
738
739 pulse_preview_mode_control();
740 show_highlighted_notice(
741 cfg.i18n && cfg.i18n.calendar_only_theme_notice ? cfg.i18n.calendar_only_theme_notice : 'Preview is set to Calendar only. Switch Preview to Booking form to inspect the form theme.',
742 'warning',
743 9000
744 );
745 }
746
747 function sync_time_picker_preview() {
748 var is_enabled = get_form().find( '[name="booking_timeslot_picker"]' ).prop( 'checked' );
749 var $preview = $( '[data-wpbc-theme-preview="1"]' );
750 var time_selectors = 'select[name^="rangetime"], select[name^="starttime"], select[name^="endtime"], select[name^="durationtime"]';
751
752 if ( w._wpbc && typeof w._wpbc.set_other_param === 'function' ) {
753 w._wpbc.set_other_param( 'is_enabled_booking_timeslot_picker', !! is_enabled );
754 }
755
756 if ( is_enabled ) {
757 if ( w._wpbc && typeof w.wpbc_hook__init_timeselector === 'function' ) {
758 w.wpbc_hook__init_timeselector();
759 }
760 return;
761 }
762 if ( typeof w.wpbc_hook__destroy_timeselector === 'function' ) {
763 w.wpbc_hook__destroy_timeselector( $preview.get( 0 ) );
764 return;
765 }
766
767 $preview.find( '.wpbc_times_selector' ).remove();
768 $preview.find( time_selectors ).show();
769 }
770
771 function refresh_preview_mode_controls() {
772 var preview_mode = $( '#wpbc_theme_preview_mode' ).val() || 'form';
773 $( '[data-wpbc-theme-form-control="1"]' ).toggleClass( 'is-visible', 'form' === preview_mode );
774 }
775
776 function set_calendar_loading( is_loading ) {
777 var $panel = $( '[data-wpbc-theme-calendar-panel="1"]' );
778
779 $panel.toggleClass( 'is-loading', !! is_loading );
780 $panel.find( '.wpbc_theme_calendar_loading' ).remove();
781
782 if ( is_loading ) {
783 $panel.append(
784 '<div class="wpbc_calendar_loading wpbc_theme_calendar_loading">' +
785 '<span class="wpbc_icn_autorenew wpbc_animation_spin"></span>&nbsp;' +
786 trim_text( cfg.i18n && cfg.i18n.loading ? cfg.i18n.loading : 'Loading' ) +
787 '</div>'
788 );
789 }
790 }
791
792 function refresh_preview() {
793 var data = collect_payload();
794
795 if ( preview_ajax && preview_ajax.readyState !== 4 ) {
796 preview_ajax.abort();
797 }
798
799 data.action = cfg.preview_action;
800 data.nonce = cfg.nonce;
801
802 set_calendar_loading( true );
803 preview_ajax = $.post( cfg.ajax_url, data )
804 .done( function ( response ) {
805 if ( response && response.success && response.data && response.data.html ) {
806 $( '[data-wpbc-theme-preview="1"]' ).replaceWith( response.data.html );
807 if ( response.data.days_selection ) {
808 cfg.days_selection = response.data.days_selection;
809 }
810 apply_form_theme();
811 apply_form_appearance();
812 apply_calendar_skin();
813 apply_time_skin();
814 ensure_calendar_only_days_selection();
815 sync_time_picker_preview();
816 return;
817 }
818
819 show_message(
820 response && response.data && response.data.message ? response.data.message : ( cfg.i18n && cfg.i18n.preview_failed ? cfg.i18n.preview_failed : 'Unable to refresh calendar preview.' ),
821 'error',
822 10000
823 );
824 } )
825 .fail( function ( xhr, text_status ) {
826 if ( 'abort' === text_status ) {
827 return;
828 }
829 show_message( cfg.i18n && cfg.i18n.preview_failed ? cfg.i18n.preview_failed : 'Unable to refresh calendar preview.', 'error', 10000 );
830 } )
831 .always( function () {
832 set_calendar_loading( false );
833 } );
834 }
835
836 function schedule_preview_refresh() {
837 clearTimeout( preview_timer );
838 preview_timer = setTimeout( refresh_preview, 180 );
839 }
840
841 function save_settings() {
842 var $button = $( '[data-wpbc-theme-save="1"]' );
843 var original_text = $button.data( 'wpbc-original-text' );
844 var data = collect_payload();
845
846 if ( ! original_text ) {
847 original_text = $button.html();
848 $button.data( 'wpbc-original-text', original_text );
849 }
850
851 data.action = cfg.action;
852 data.nonce = cfg.nonce;
853
854 $button.addClass( 'disabled' ).attr( 'aria-disabled', 'true' );
855 $button.find( '.in-button-text' ).html( '&nbsp;&nbsp;' + trim_text( cfg.i18n && cfg.i18n.saving ? cfg.i18n.saving : 'Saving' ) + '...' );
856
857 $.post( cfg.ajax_url, data )
858 .done( function ( response ) {
859 if ( response && response.success ) {
860 show_message( response.data && response.data.message ? response.data.message : ( cfg.i18n && cfg.i18n.saved ? cfg.i18n.saved : 'Saved' ), 'success', 3000 );
861 cfg.settings = response.data && response.data.settings ? response.data.settings : cfg.settings;
862 return;
863 }
864
865 show_message(
866 response && response.data && response.data.message ? response.data.message : ( cfg.i18n && cfg.i18n.save_failed ? cfg.i18n.save_failed : 'Unable to save appearance settings.' ),
867 'error',
868 10000
869 );
870 } )
871 .fail( function () {
872 show_message( cfg.i18n && cfg.i18n.save_failed ? cfg.i18n.save_failed : 'Unable to save appearance settings.', 'error', 10000 );
873 } )
874 .always( function () {
875 $button.removeClass( 'disabled' ).removeAttr( 'aria-disabled' ).html( original_text );
876 } );
877 }
878
879 function bind_events() {
880 $( document ).on( 'click', '.wpbc_theme_rightbar_tabs [role="tab"]', function ( event ) {
881 event.preventDefault();
882 switch_panel( $( this ) );
883 } );
884
885 $( document ).on( 'click', '.wpbc_theme_premium_dismiss a', function ( event ) {
886 event.stopPropagation();
887 } );
888
889 $( document ).on( 'click', '.wpbc_theme_rightbar_panels .wpbc_ui__collapsible_group > .group__header', function ( event ) {
890 event.preventDefault();
891 toggle_group( $( this ) );
892 } );
893
894 $( document ).on( 'click', '[data-wpbc-theme-save="1"]', function ( event ) {
895 event.preventDefault();
896 if ( ! $( this ).hasClass( 'disabled' ) ) {
897 save_settings();
898 }
899 } );
900
901 $( document ).on( 'submit', '[data-wpbc-theme-settings-form="1"]', function () {
902 return true;
903 } );
904
905 $( document ).on( 'change', '[name="booking_form_theme"]', function () {
906 apply_form_theme();
907 apply_related_skins_for_theme( $( this ).val() || '' );
908 show_calendar_only_theme_notice();
909 } );
910
911 $( document ).on( 'change', '[name="booking_form_style"]', function () {
912 sync_form_style_choice();
913 apply_form_theme();
914 apply_form_appearance();
915 apply_related_skins_for_theme( $( '#booking_form_theme' ).val() || '' );
916 show_calendar_only_theme_notice();
917 schedule_preview_refresh();
918 } );
919
920 $( document ).on( 'input change', '[data-wpbc-theme-appearance-control]', function () {
921 // Coloris emits continuous input events. Accent and appearance values are
922 // CSS-only, so update the existing preview without rebuilding it by AJAX.
923 apply_form_appearance();
924 } );
925
926 $( document ).on( 'change', '[data-wpbc-theme-accent-toggle="1"]', function () {
927 $( '[data-wpbc-theme-accent-dependent="1"]' ).toggle( $( this ).prop( 'checked' ) );
928 apply_form_appearance();
929 } );
930
931 $( document ).on( 'change', '[data-wpbc-theme-calendar-skin="1"]', function () {
932 apply_calendar_skin();
933 } );
934
935 $( document ).on( 'change', '[data-wpbc-theme-time-skin="1"]', function () {
936 apply_time_skin();
937 } );
938
939 $( document ).on( 'change', '[name="booking_timeslot_picker"]', function () {
940 sync_time_picker_preview();
941 schedule_preview_refresh();
942 } );
943
944 $( document ).on( 'change', '[data-wpbc-theme-preview-notice]', function () {
945 maybe_show_preview_notice( $( this ) );
946 } );
947
948 $( document ).on( 'change', '#wpbc_theme_resource_id, #wpbc_theme_months_count, #wpbc_theme_custom_form', function () {
949 schedule_preview_refresh();
950 } );
951
952 $( document ).on( 'change', '#wpbc_theme_preview_mode', function () {
953 refresh_preview_mode_controls();
954 schedule_preview_refresh();
955 } );
956 }
957
958 $( function () {
959 if ( ! $( '[data-wpbc-theme-page="1"]' ).length ) {
960 return;
961 }
962
963 bind_events();
964 if ( w.Coloris ) {
965 w.Coloris( {
966 el: '.wpbc_theme_coloris',
967 alpha: false,
968 format: 'hex',
969 themeMode: 'auto'
970 } );
971 }
972 refresh_preview_mode_controls();
973 apply_form_theme();
974 apply_form_appearance();
975 ensure_calendar_only_days_selection();
976 sync_time_picker_preview();
977 } );
978 }( jQuery, window ) );
979