PluginProbe
Booking Calendar / 11.5
Booking Calendar v11.5
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-add-booking / _src / add_booking_page.js

add_booking_page.js in Booking Calendar 11.5, at includes/page-add-booking/_src/add_booking_page.js

355 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /** Add Booking administrator inspector interactions. */
2 ( function ( $ ) {
3 'use strict';
4
5 var active_days_selection_override = '';
6 var days_selection_enforcement_timers = [];
7
8 /**
9 * Show the panel controlled by one compact right-sidebar tab.
10 *
11 * @param {jQuery} $tab Selected tab button.
12 * @return {void}
13 */
14 function switch_right_panel( $tab ) {
15 var panel_id = $tab.attr( 'aria-controls' );
16 var $tabs = $tab.closest( '.wpbc_add_booking__rightbar_tabs' ).find( '[role="tab"]' );
17 var $panels = $( '.wpbc_add_booking__rightbar' ).find( '[role="tabpanel"]' );
18
19 if ( ! panel_id || ! $( '#' + panel_id ).length ) {
20 return;
21 }
22
23 $tabs.attr( 'aria-selected', 'false' );
24 $tab.attr( 'aria-selected', 'true' );
25 $panels.attr( { hidden: true, 'aria-hidden': 'true' } );
26 $( '#' + panel_id ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
27 }
28
29 /**
30 * Expand an inspector group and focus one of its controls.
31 *
32 * The shared collapsible controller is used when available so exclusive
33 * groups and ARIA state stay synchronized. The header click is a safe
34 * fallback for older Booking Calendar admin bundles.
35 *
36 * @param {string} group_name Group data key.
37 * @param {string} focus_selector Optional control to focus after expansion.
38 * @return {void}
39 */
40 function open_settings_group( group_name, focus_selector ) {
41 var $group = $( '.wpbc_add_booking__inspector_settings .wpbc_ui__collapsible_group[data-group="' + group_name + '"]' ).first();
42 var root;
43 var controller;
44
45 if ( ! $group.length ) {
46 return;
47 }
48
49 root = $group.closest( '.wpbc_collapsible' ).get( 0 );
50 controller = root && root.__wpbc_collapsible_instance ? root.__wpbc_collapsible_instance : null;
51
52 if ( controller && 'function' === typeof controller.expand ) {
53 controller.expand( $group.get( 0 ) );
54 } else {
55 $group.siblings( '.wpbc_ui__collapsible_group' ).each( function () {
56 var $sibling = $( this );
57
58 $sibling.removeClass( 'is-open' );
59 $sibling.children( '.group__header' ).attr( 'aria-expanded', 'false' );
60 $sibling.children( '.group__fields' ).attr( { hidden: true, 'aria-hidden': 'true' } );
61 } );
62 $group.addClass( 'is-open' );
63 $group.children( '.group__header' ).attr( 'aria-expanded', 'true' );
64 $group.children( '.group__fields' ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
65 }
66
67 window.requestAnimationFrame( function () {
68 $group.get( 0 ).scrollIntoView( { behavior: 'smooth', block: 'start' } );
69 if ( focus_selector ) {
70 window.setTimeout( function () {
71 $( focus_selector ).first().trigger( 'focus' );
72 }, 250 );
73 }
74 } );
75 }
76
77 /**
78 * Synchronize Booking Tools status links with their current toggle values.
79 *
80 * @return {void}
81 */
82 function refresh_booking_tools_summary() {
83 var $summary = $( '.wpbc_add_booking__setup_summary' ).first();
84 var enabled_label;
85 var disabled_label;
86
87 if ( ! $summary.length ) {
88 return;
89 }
90
91 enabled_label = $summary.attr( 'data-wpbc-add-booking-enabled-label' ) || 'Enabled';
92 disabled_label = $summary.attr( 'data-wpbc-add-booking-disabled-label' ) || 'Disabled';
93
94 $summary.find( '[data-wpbc-add-booking-summary="emails"]' ).text(
95 $( '#is_send_email_for_pending' ).is( ':checked' ) ? enabled_label : disabled_label
96 );
97 $summary.find( '[data-wpbc-add-booking-summary="allow-past"]' ).text(
98 $( '#is_allow_bookings_in_past' ).is( ':checked' ) ? enabled_label : disabled_label
99 );
100 }
101
102 /**
103 * Get the Add Booking date-selection radio container.
104 *
105 * @return {jQuery} Date-selection container, when rendered.
106 */
107 function get_days_selection_container() {
108 return $( '[data-wpbc-add-booking-days-selection="1"]' ).first();
109 }
110
111 /**
112 * Normalize calendar engine modes to the three administrator radio choices.
113 *
114 * @param {string} mode Calendar or radio mode.
115 * @return {string} single, multiple, range, or an empty string.
116 */
117 function normalize_days_selection_mode( mode ) {
118 mode = String( mode || '' );
119
120 if ( 'fixed' === mode || 'dynamic' === mode || 'range' === mode ) {
121 return 'range';
122 }
123
124 return 'single' === mode || 'multiple' === mode ? mode : '';
125 }
126
127 /**
128 * Get the current Add Booking resource ID from the radio control context.
129 *
130 * @return {number} Positive resource ID, or zero when unavailable.
131 */
132 function get_days_selection_resource_id() {
133 var resource_id = parseInt( get_days_selection_container().attr( 'data-wpbc-resource-id' ), 10 );
134
135 if ( ! resource_id && window.wpbc_add_booking_component_context ) {
136 resource_id = parseInt( window.wpbc_add_booking_component_context.resource_id, 10 );
137 }
138
139 return resource_id > 0 ? resource_id : 0;
140 }
141
142 /**
143 * Read one calendar parameter without exposing page state globally.
144 *
145 * @param {number} resource_id Booking resource ID.
146 * @param {string} parameter_name Calendar parameter name.
147 * @return {*} Current parameter value, or null when the calendar is unavailable.
148 */
149 function get_calendar_parameter( resource_id, parameter_name ) {
150 if ( ! window._wpbc || ! window._wpbc.calendar || 'function' !== typeof window._wpbc.calendar__get_param_value ) {
151 return null;
152 }
153
154 return window._wpbc.calendar__get_param_value( resource_id, parameter_name );
155 }
156
157 /**
158 * Normalize an array or comma-separated calendar parameter into integers.
159 *
160 * @param {Array|number|string} parameter_value Calendar parameter value.
161 * @param {Array} fallback_value Value returned when no valid numbers exist.
162 * @return {Array} Integer values.
163 */
164 function normalize_calendar_number_list( parameter_value, fallback_value ) {
165 var values = Array.isArray( parameter_value ) ? parameter_value : String( parameter_value || '' ).split( ',' );
166 var normalized_values = [];
167
168 $.each( values, function ( index, number_value ) {
169 var parsed_number = parseInt( number_value, 10 );
170
171 if ( ! isNaN( parsed_number ) ) {
172 normalized_values.push( parsed_number );
173 }
174 } );
175
176 return normalized_values.length ? normalized_values : fallback_value;
177 }
178
179 /**
180 * Get the fixed/dynamic engine to use for the Range days radio choice.
181 *
182 * @return {string} fixed or dynamic.
183 */
184 function get_range_engine_mode() {
185 var range_engine_mode = String( get_days_selection_container().attr( 'data-wpbc-range-engine-mode' ) || 'dynamic' );
186
187 return 'fixed' === range_engine_mode ? 'fixed' : 'dynamic';
188 }
189
190 /**
191 * Update the checked radio and visible setup summary from an effective mode.
192 *
193 * @param {string} mode Calendar or radio mode.
194 * @return {void}
195 */
196 function sync_days_selection_controls( mode ) {
197 var normalized_mode = normalize_days_selection_mode( mode );
198 var $container = get_days_selection_container();
199 var $radio;
200 var mode_label;
201
202 if ( ! normalized_mode || ! $container.length ) {
203 return;
204 }
205
206 $radio = $container.find( 'input[name="wpbc_add_booking_days_selection_mode"][value="' + normalized_mode + '"]' );
207 if ( 1 !== $radio.length ) {
208 return;
209 }
210
211 $radio.prop( 'checked', true );
212 mode_label = $radio.attr( 'data-wpbc-days-selection-label' ) || normalized_mode;
213 $( '[data-wpbc-add-booking-summary="days-selection"]' ).text( mode_label );
214 }
215
216 /**
217 * Clear selected dates before changing their selection semantics.
218 *
219 * Customer fields remain untouched. Existing calendar helpers are used when
220 * available so Datepick state and the hidden selected-date field stay aligned.
221 *
222 * @param {number} resource_id Booking resource ID.
223 * @return {void}
224 */
225 function clear_selected_booking_dates( resource_id ) {
226 var $date_field = $( '#date_booking' + resource_id );
227
228 if ( ! $date_field.length || ! String( $date_field.val() || '' ).trim() ) {
229 return;
230 }
231
232 if ( 'function' === typeof window.wpbc_calendar__unselect_all_dates ) {
233 window.wpbc_calendar__unselect_all_dates( resource_id );
234 } else {
235 $date_field.val( '' );
236 }
237
238 if ( 'function' === typeof window.wpbc_disable_time_fields_in_booking_form ) {
239 window.wpbc_disable_time_fields_in_booking_form( resource_id );
240 }
241 }
242
243 /**
244 * Apply one radio mode through the shared immediate calendar helpers.
245 *
246 * Range mode retains the configured fixed/dynamic subtype and its existing
247 * number-of-days and weekday parameters. No settings are saved.
248 *
249 * @param {string} mode Requested radio mode.
250 * @param {boolean} clear_dates Whether an existing selection must be cleared.
251 * @return {boolean} True when the requested helper was applied or already active.
252 */
253 function apply_days_selection_mode( mode, clear_dates ) {
254 var normalized_mode = normalize_days_selection_mode( mode );
255 var resource_id = get_days_selection_resource_id();
256 var desired_engine_mode = 'range' === normalized_mode ? get_range_engine_mode() : normalized_mode;
257 var current_engine_mode;
258 var fixed_days_number;
259
260 if ( ! normalized_mode || ! resource_id ) {
261 return false;
262 }
263
264 current_engine_mode = String( get_calendar_parameter( resource_id, 'days_select_mode' ) || '' );
265 if ( desired_engine_mode === current_engine_mode ) {
266 sync_days_selection_controls( normalized_mode );
267 return true;
268 }
269
270 if ( clear_dates ) {
271 clear_selected_booking_dates( resource_id );
272 }
273
274 if ( 'single' === normalized_mode && 'function' === typeof window.wpbc_cal_days_select__single ) {
275 window.wpbc_cal_days_select__single( resource_id );
276 } else if ( 'multiple' === normalized_mode && 'function' === typeof window.wpbc_cal_days_select__multiple ) {
277 window.wpbc_cal_days_select__multiple( resource_id );
278 } else if ( 'range' === normalized_mode && 'fixed' === desired_engine_mode && 'function' === typeof window.wpbc_cal_days_select__fixed ) {
279 fixed_days_number = parseInt( get_calendar_parameter( resource_id, 'fixed__days_num' ), 10 );
280 window.wpbc_cal_days_select__fixed(
281 resource_id,
282 fixed_days_number > 0 ? fixed_days_number : 3,
283 normalize_calendar_number_list( get_calendar_parameter( resource_id, 'fixed__week_days__start' ), [ -1 ] )
284 );
285 } else if ( 'range' === normalized_mode && 'function' === typeof window.wpbc_cal_days_select__range_mode ) {
286 window.wpbc_cal_days_select__range_mode( resource_id );
287 } else {
288 return false;
289 }
290
291 sync_days_selection_controls( normalized_mode );
292 return true;
293 }
294
295 /**
296 * Synchronize controls with the calendar, or enforce a user-selected override.
297 *
298 * @return {void}
299 */
300 function synchronize_days_selection_mode() {
301 var resource_id = get_days_selection_resource_id();
302 var current_engine_mode;
303
304 if ( ! resource_id ) {
305 return;
306 }
307
308 if ( active_days_selection_override ) {
309 apply_days_selection_mode( active_days_selection_override, false );
310 return;
311 }
312
313 current_engine_mode = get_calendar_parameter( resource_id, 'days_select_mode' );
314 sync_days_selection_controls( current_engine_mode );
315 }
316
317 /**
318 * Recheck mode after the selected Booking Form's legacy delayed initializer.
319 *
320 * Existing timers are cancelled so repeated clicks cannot accumulate work.
321 * Reapplication occurs only when the calendar engine mode was changed by a
322 * later initializer, avoiding unnecessary calendar renders.
323 *
324 * @return {void}
325 */
326 function schedule_days_selection_synchronization() {
327 $.each( days_selection_enforcement_timers, function ( index, timer_id ) {
328 window.clearTimeout( timer_id );
329 } );
330 days_selection_enforcement_timers = [];
331
332 $.each( [ 0, 120, 1150, 2200 ], function ( index, delay ) {
333 days_selection_enforcement_timers.push( window.setTimeout( synchronize_days_selection_mode, delay ) );
334 } );
335 }
336
337 $( document ).on( 'click', '.wpbc_add_booking__rightbar_tabs [role="tab"]', function () {
338 switch_right_panel( $( this ) );
339 } );
340
341 $( document ).on( 'click', '.wpbc_add_booking__setup_summary_link', function ( event ) {
342 event.preventDefault();
343 open_settings_group( $( this ).attr( 'data-wpbc-add-booking-open-group' ), $( this ).attr( 'data-wpbc-add-booking-focus' ) || '' );
344 } );
345
346 $( document ).on( 'change', '#is_send_email_for_pending, #is_allow_bookings_in_past', refresh_booking_tools_summary );
347 $( document ).on( 'click', 'input[name="wpbc_add_booking_days_selection_mode"]', function () {
348 active_days_selection_override = normalize_days_selection_mode( $( this ).val() );
349 apply_days_selection_mode( active_days_selection_override, true );
350 schedule_days_selection_synchronization();
351 } );
352 $( refresh_booking_tools_summary );
353 $( schedule_days_selection_synchronization );
354 }( jQuery ) );
355