PluginProbe
Booking Calendar / 11.6.1
Booking Calendar v11.6.1
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 10.11.2 All 203 releases
booking / includes / page-availability-general / _src / availability_general_page.js

availability_general_page.js in Booking Calendar 11.6.1, at includes/page-availability-general/_src/availability_general_page.js

1,084 lines 38.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * General Availability UI.
3 */
4 ( function ( $, w ) {
5 'use strict';
6
7 var cfg = w.wpbc_availability_general_page || {};
8 var preview_timer = 0;
9 var preview_frame = 0;
10 var preview_ajax = null;
11 var observer = null;
12 var preview_unavailable_classes = 'wpbc_ag_preview_unavailable wpbc_ag_preview_weekday_unavailable wpbc_ag_preview_from_today_unavailable wpbc_ag_preview_limit_available_from_today wpbc_ag_preview_buffer_unavailable weekday_unavailable from_today_unavailable limit_available_from_today buffer_unavailable';
13
14 function trim_text( value ) {
15 return String( value || '' ).trim();
16 }
17
18 function switch_panel( $tab ) {
19 var panel_id = $tab.attr( 'aria-controls' );
20 var $tabs = $tab.closest( '.wpbc_ag_rightbar_tabs' ).find( '[role="tab"]' );
21 var $panels = $( '.wpbc_ag_rightbar_panels [role="tabpanel"]' );
22
23 $tabs.attr( 'aria-selected', 'false' );
24 $tab.attr( 'aria-selected', 'true' );
25
26 $panels.attr( 'hidden', 'hidden' ).attr( 'aria-hidden', 'true' );
27 $( '#' + panel_id ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
28 }
29
30 function toggle_group( $button ) {
31 var $group = $button.closest( '.wpbc_ui__collapsible_group' );
32 var $fields = $group.find( '> .group__fields' );
33 var is_open = $group.hasClass( 'is-open' );
34
35 $group.toggleClass( 'is-open', ! is_open );
36 $button.attr( 'aria-expanded', is_open ? 'false' : 'true' );
37 $fields.prop( 'hidden', is_open ).attr( 'aria-hidden', is_open ? 'true' : 'false' );
38 }
39
40 function close_group( $group ) {
41 var $button = $group.find( '> .group__header' );
42 var $fields = $group.find( '> .group__fields' );
43
44 $group.removeClass( 'is-open' );
45 $button.attr( 'aria-expanded', 'false' );
46 $fields.prop( 'hidden', true ).attr( 'aria-hidden', 'true' );
47 }
48
49 function open_group( group_name, is_exclusive ) {
50 var $group = $( '.wpbc_ui__collapsible_group[data-group="' + group_name + '"]' );
51 var $button = $group.find( '> .group__header' );
52 var $fields = $group.find( '> .group__fields' );
53
54 if ( ! $group.length ) {
55 return;
56 }
57
58 if ( is_exclusive ) {
59 $group.siblings( '.wpbc_ui__collapsible_group' ).each( function () {
60 close_group( $( this ) );
61 } );
62 }
63
64 $group.addClass( 'is-open' );
65 $button.attr( 'aria-expanded', 'true' );
66 $fields.prop( 'hidden', false ).attr( 'aria-hidden', 'false' );
67 }
68
69 function scroll_to_group( group_name ) {
70 var $group = $( '.wpbc_ui__collapsible_group[data-group="' + group_name + '"]' );
71 var $scroll_parent = $();
72 var scroll_parent_el;
73 var group_el;
74 var scroll_top;
75 var parent_rect;
76 var group_rect;
77
78 if ( ! $group.length ) {
79 return;
80 }
81
82 $group.parents().each( function () {
83 var $candidate = $( this );
84 var overflow_y = $candidate.css( 'overflow-y' );
85
86 if (
87 $candidate.hasClass( 'simplebar-content-wrapper' )
88 || (
89 /(auto|scroll)/.test( overflow_y )
90 && this.scrollHeight > this.clientHeight
91 )
92 ) {
93 $scroll_parent = $candidate;
94 return false;
95 }
96 } );
97
98 if ( ! $scroll_parent.length ) {
99 $scroll_parent = $group.closest( '.wpbc_ui_el__vert_right_bar__content' ).find( '.simplebar-content-wrapper' ).first();
100 }
101
102 if ( ! $scroll_parent.length ) {
103 $group.get( 0 ).scrollIntoView( { block: 'nearest' } );
104 return;
105 }
106
107 scroll_parent_el = $scroll_parent.get( 0 );
108 group_el = $group.get( 0 );
109 parent_rect = scroll_parent_el.getBoundingClientRect();
110 group_rect = group_el.getBoundingClientRect();
111 scroll_top = $scroll_parent.scrollTop() + group_rect.top - parent_rect.top - 10;
112
113 $scroll_parent.stop().animate( { scrollTop: Math.max( 0, scroll_top ) }, 180 );
114 }
115
116 function apply_open_section_from_url() {
117 var section_groups = {
118 weekdays: 'general-availability-weekdays',
119 from_today: 'general-availability-from-today',
120 buffer: 'general-availability-buffer',
121 working_time: 'general-availability-working-time'
122 };
123 var group_name = section_groups[ cfg.open_section ] || '';
124
125 if ( '' === group_name ) {
126 return;
127 }
128
129 open_group( group_name, true );
130 $.each( [ 120, 650 ], function ( index, delay ) {
131 setTimeout( function () {
132 scroll_to_group( group_name );
133 }, delay );
134 } );
135 }
136
137 function refresh_buffer_fields() {
138 var value = $( 'input[name="booking_unavailable_extra_in_out"]:checked' ).val() || '';
139
140 $( '.wpbc_ag_buffer_fields' ).each( function () {
141 var $panel = $( this );
142 $panel.toggleClass( 'is-visible', $panel.data( 'buffer-panel' ) === value );
143 } );
144 }
145
146 function is_buffer_available() {
147 return ! ( cfg.is_buffer_available === false || cfg.is_buffer_available === 'false' || cfg.is_buffer_available === 0 || cfg.is_buffer_available === '0' );
148 }
149
150 function is_available_limit_available() {
151 return ! ( cfg.is_available_limit_available === false || cfg.is_available_limit_available === 'false' || cfg.is_available_limit_available === 0 || cfg.is_available_limit_available === '0' );
152 }
153
154 function sync_range_from_select( select ) {
155 var $select = $( select );
156 var name = $select.attr( 'name' );
157 var selected_index = $select.prop( 'selectedIndex' );
158 var selected_text = trim_text( $select.find( 'option:selected' ).text() );
159 var $range = $( '[data-wpbc-ag-range-for="' + name + '"]' );
160 var $value = $( '[data-wpbc-ag-range-value-for="' + name + '"]' );
161
162 if ( ! $range.length ) {
163 return;
164 }
165
166 $range.val( selected_index < 0 ? 0 : selected_index );
167 $value.text( selected_text );
168 }
169
170 function sync_select_from_range( range ) {
171 var $range = $( range );
172 var name = $range.attr( 'data-wpbc-ag-range-for' );
173 var $select = $( '[name="' + name + '"]' );
174 var index = parseInt( $range.val(), 10 ) || 0;
175
176 if ( ! $select.length ) {
177 return;
178 }
179
180 $select.prop( 'selectedIndex', index );
181 sync_range_from_select( $select );
182 }
183
184 function sync_all_ranges() {
185 $( '[data-wpbc-ag-range-for]' ).each( function () {
186 var name = $( this ).attr( 'data-wpbc-ag-range-for' );
187 sync_range_from_select( $( '[name="' + name + '"]' ).first() );
188 } );
189 }
190
191 function step_select_value( button ) {
192 var $button = $( button );
193 var name = $button.attr( 'data-wpbc-ag-stepper' );
194 var step = parseInt( $button.attr( 'data-step' ), 10 ) || 0;
195 var $select = $( '[name="' + name + '"]' ).first();
196 var current_index;
197 var next_index;
198
199 if ( ! $select.length || $select.prop( 'disabled' ) ) {
200 return;
201 }
202
203 current_index = $select.prop( 'selectedIndex' );
204 next_index = Math.max( 0, Math.min( $select.find( 'option' ).length - 1, current_index + step ) );
205
206 if ( next_index === current_index ) {
207 return;
208 }
209
210 $select.prop( 'selectedIndex', next_index ).trigger( 'change' );
211 }
212
213 function get_form() {
214 return $( '[data-wpbc-ag-settings-form="1"]' ).first();
215 }
216
217 function collect_settings() {
218 var $form = get_form();
219 var weekdays = [];
220
221 $form.find( 'input[name="booking_unavailable_days[]"]:checked' ).each( function () {
222 weekdays.push( parseInt( this.value, 10 ) );
223 } );
224
225 return {
226 weekdays: weekdays,
227 booking_unavailable_days_num_from_today: $form.find( '[name="booking_unavailable_days_num_from_today"]' ).val() || '0',
228 booking_available_days_num_from_today: $form.find( '[name="booking_available_days_num_from_today"]' ).val() || '',
229 booking_unavailable_extra_in_out: $form.find( '[name="booking_unavailable_extra_in_out"]:checked' ).val() || '',
230 booking_unavailable_extra_minutes_in: $form.find( '[name="booking_unavailable_extra_minutes_in"]' ).val() || '',
231 booking_unavailable_extra_minutes_out: $form.find( '[name="booking_unavailable_extra_minutes_out"]' ).val() || '',
232 booking_unavailable_extra_days_in: $form.find( '[name="booking_unavailable_extra_days_in"]' ).val() || '',
233 booking_unavailable_extra_days_out: $form.find( '[name="booking_unavailable_extra_days_out"]' ).val() || '',
234 working_time: get_working_time_settings_from_form()
235 };
236 }
237
238 function set_select_value( name, value ) {
239 var $field = get_form().find( '[name="' + name + '"]' ).first();
240
241 if ( ! $field.length ) {
242 return;
243 }
244
245 $field.val( value );
246 if ( String( $field.val() ) !== String( value ) ) {
247 $field.prop( 'selectedIndex', 0 );
248 }
249 }
250
251 function apply_settings_to_form( settings ) {
252 var $form = get_form();
253 var weekdays = settings && settings.weekdays ? settings.weekdays : [];
254
255 if ( ! $form.length || ! settings ) {
256 return;
257 }
258
259 $form.find( 'input[name="booking_unavailable_days[]"]' ).prop( 'checked', false );
260 $.each( weekdays, function ( index, day_num ) {
261 $form.find( 'input[name="booking_unavailable_days[]"][value="' + parseInt( day_num, 10 ) + '"]' ).prop( 'checked', true );
262 } );
263
264 set_select_value( 'booking_unavailable_days_num_from_today', settings.booking_unavailable_days_num_from_today || '0' );
265 set_select_value( 'booking_available_days_num_from_today', settings.booking_available_days_num_from_today || '' );
266 set_select_value( 'booking_unavailable_extra_minutes_in', settings.booking_unavailable_extra_minutes_in || '' );
267 set_select_value( 'booking_unavailable_extra_minutes_out', settings.booking_unavailable_extra_minutes_out || '' );
268 set_select_value( 'booking_unavailable_extra_days_in', settings.booking_unavailable_extra_days_in || '' );
269 set_select_value( 'booking_unavailable_extra_days_out', settings.booking_unavailable_extra_days_out || '' );
270
271 $form.find( 'input[name="booking_unavailable_extra_in_out"]' ).prop( 'checked', false );
272 $form.find( 'input[name="booking_unavailable_extra_in_out"][value="' + ( settings.booking_unavailable_extra_in_out || '' ) + '"]' ).prop( 'checked', true );
273 apply_working_time_settings_to_form( settings.working_time || {}, $( '#wpbc_ag_resource_id' ).val() );
274
275 refresh_buffer_fields();
276 sync_all_ranges();
277 schedule_preview_refresh();
278 }
279
280 function date_from_sql( sql_date ) {
281 var parts = String( sql_date || '' ).split( '-' );
282 if ( parts.length !== 3 ) {
283 return null;
284 }
285 return new Date( parseInt( parts[0], 10 ), parseInt( parts[1], 10 ) - 1, parseInt( parts[2], 10 ), 0, 0, 0 );
286 }
287
288 function get_today_date() {
289 var arr = w._wpbc && typeof w._wpbc.get_other_param === 'function' ? w._wpbc.get_other_param( 'today_arr' ) : null;
290 if ( arr && arr.length >= 3 ) {
291 return new Date( parseInt( arr[0], 10 ), parseInt( arr[1], 10 ) - 1, parseInt( arr[2], 10 ), 0, 0, 0 );
292 }
293 var now = new Date();
294 return new Date( now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0 );
295 }
296
297 function get_real_today_date() {
298 var arr = w._wpbc && typeof w._wpbc.get_other_param === 'function' ? w._wpbc.get_other_param( 'time_local_arr' ) : null;
299 if ( arr && arr.length >= 3 ) {
300 return new Date( parseInt( arr[0], 10 ), parseInt( arr[1], 10 ) - 1, parseInt( arr[2], 10 ), 0, 0, 0 );
301 }
302 return get_today_date();
303 }
304
305 function days_between( date_a, date_b ) {
306 return Math.floor( ( date_a.getTime() - date_b.getTime() ) / 86400000 );
307 }
308
309 function add_days( date, days ) {
310 var shifted_date = new Date( date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0 );
311 shifted_date.setDate( shifted_date.getDate() + days );
312 return shifted_date;
313 }
314
315 function date_to_sql( date ) {
316 var month = String( date.getMonth() + 1 );
317 var day = String( date.getDate() );
318
319 if ( month.length < 2 ) {
320 month = '0' + month;
321 }
322 if ( day.length < 2 ) {
323 day = '0' + day;
324 }
325
326 return date.getFullYear() + '-' + month + '-' + day;
327 }
328
329 function get_sql_date_from_cell( cell ) {
330 var classes = String( cell.className || '' ).split( /\s+/ );
331 var i;
332 for ( i = 0; i < classes.length; i++ ) {
333 if ( classes[i].indexOf( 'sql_date_' ) === 0 ) {
334 return classes[i].replace( 'sql_date_', '' );
335 }
336 }
337 return '';
338 }
339
340 function unavailable_from_today_applies( cell_date, today_date, value ) {
341 var minutes;
342 var now;
343 var unavailable_until;
344
345 if ( ! value || value === '0' ) {
346 return false;
347 }
348
349 if ( /m$/.test( value ) ) {
350 minutes = parseInt( value, 10 );
351 if ( ! minutes ) {
352 return false;
353 }
354 now = new Date();
355 unavailable_until = new Date( now.getTime() + ( ( minutes - 1 ) * 60000 ) );
356 unavailable_until = new Date( unavailable_until.getFullYear(), unavailable_until.getMonth(), unavailable_until.getDate(), 0, 0, 0 );
357 return cell_date.getTime() <= unavailable_until.getTime();
358 }
359
360 return days_between( cell_date, today_date ) < parseInt( value, 10 );
361 }
362
363 function get_option_text( selector ) {
364 var text = $( selector ).find( 'option:selected' ).text();
365 return trim_text( text );
366 }
367
368 function get_days_value( value ) {
369 if ( ! value || ! /d$/.test( value ) ) {
370 return 0;
371 }
372 return parseInt( value, 10 ) || 0;
373 }
374
375 function time_to_seconds( time ) {
376 var parts = String( time || '' ).split( ':' );
377 var hours;
378 var mins;
379
380 if ( parts.length < 2 ) {
381 return 0;
382 }
383
384 hours = Math.max( 0, Math.min( 24, parseInt( parts[0], 10 ) || 0 ) );
385 mins = hours === 24 ? 0 : Math.max( 0, Math.min( 59, parseInt( parts[1], 10 ) || 0 ) );
386
387 return Math.min( 86400, ( hours * 3600 ) + ( mins * 60 ) );
388 }
389
390 function seconds_to_time( seconds ) {
391 var hours;
392 var mins;
393
394 seconds = Math.max( 0, Math.min( 86400, parseInt( seconds, 10 ) || 0 ) );
395 hours = Math.floor( seconds / 3600 );
396 mins = Math.floor( ( seconds % 3600 ) / 60 );
397
398 return ( hours < 10 ? '0' : '' ) + hours + ':' + ( mins < 10 ? '0' : '' ) + mins;
399 }
400
401 function collect_working_time_weekdays( prefix ) {
402 var $form = get_form();
403 var weekdays = {};
404
405 $form.find( '[data-wpbc-working-time-weekdays="' + prefix + '"] .wpbc_ag_working_time_row' ).each( function () {
406 var $row = $( this );
407 var day = parseInt( $row.find( 'input[type="checkbox"]' ).val(), 10 );
408
409 weekdays[ day ] = [];
410 if ( ! $row.find( 'input[type="checkbox"]' ).prop( 'checked' ) ) {
411 return;
412 }
413
414 weekdays[ day ].push( {
415 start_second: time_to_seconds( $row.find( '.wpbc_ag_working_time_start' ).val() ),
416 end_second: time_to_seconds( $row.find( '.wpbc_ag_working_time_end' ).val() )
417 } );
418 } );
419
420 return weekdays;
421 }
422
423 function set_working_time_weekdays( prefix, weekdays ) {
424 var $wrap = get_form().find( '[data-wpbc-working-time-weekdays="' + prefix + '"]' );
425
426 $wrap.find( '.wpbc_ag_working_time_row' ).each( function () {
427 var $row = $( this );
428 var day = parseInt( $row.find( 'input[type="checkbox"]' ).val(), 10 );
429 var intervals = weekdays && weekdays[ day ] ? weekdays[ day ] : [];
430 var interval = intervals.length ? intervals[0] : { start_second: 32400, end_second: 64800 };
431
432 $row.find( 'input[type="checkbox"]' ).prop( 'checked', intervals.length > 0 );
433 $row.find( '.wpbc_ag_working_time_start' ).val( seconds_to_time( interval.start_second ) );
434 $row.find( '.wpbc_ag_working_time_end' ).val( seconds_to_time( interval.end_second ) );
435 } );
436 }
437
438 function refresh_working_time_panels() {
439 var is_enabled = get_form().find( 'input[name="booking_working_time_enabled"]' ).prop( 'checked' );
440 var mode = get_form().find( 'input[name="booking_working_time_resource_mode"]:checked' ).val() || 'inherit';
441
442 get_form()
443 .find( '.wpbc_ag_working_time_block' )
444 .toggleClass( 'is-disabled', ! is_enabled )
445 .find( 'input, select, button' )
446 .prop( 'disabled', ! is_enabled );
447
448 get_form().find( '[data-wpbc-working-time-resource-custom]' ).toggleClass( 'is-visible', mode === 'custom' );
449 }
450
451 function get_working_time_settings_from_form() {
452 var $form = get_form();
453 var resourceId = parseInt( $form.find( '[data-wpbc-working-time-resource-id]' ).val(), 10 ) || parseInt( $( '#wpbc_ag_resource_id' ).val(), 10 ) || 0;
454 var workingTime = $.extend( true, {}, cfg.settings && cfg.settings.working_time ? cfg.settings.working_time : ( cfg.default_settings && cfg.default_settings.working_time ? cfg.default_settings.working_time : {} ) );
455
456 if ( ! workingTime.default ) {
457 workingTime.default = {};
458 }
459 if ( ! workingTime.resources ) {
460 workingTime.resources = {};
461 }
462
463 workingTime.enabled = $form.find( 'input[name="booking_working_time_enabled"]' ).prop( 'checked' ) ? 'On' : 'Off';
464 workingTime.default.weekdays = collect_working_time_weekdays( 'booking_working_time_default' );
465
466 if ( resourceId > 0 ) {
467 workingTime.resources[ resourceId ] = {
468 mode: $form.find( 'input[name="booking_working_time_resource_mode"]:checked' ).val() || 'inherit',
469 weekdays: collect_working_time_weekdays( 'booking_working_time_resource' )
470 };
471 }
472
473 return workingTime;
474 }
475
476 function apply_working_time_settings_to_form( workingTime, resourceId ) {
477 var resourceSettings;
478
479 workingTime = workingTime || {};
480 resourceId = parseInt( resourceId, 10 ) || parseInt( $( '#wpbc_ag_resource_id' ).val(), 10 ) || 0;
481 resourceSettings = workingTime.resources && workingTime.resources[ resourceId ] ? workingTime.resources[ resourceId ] : {
482 mode: 'inherit',
483 weekdays: workingTime.default && workingTime.default.weekdays ? workingTime.default.weekdays : {}
484 };
485
486 get_form().find( 'input[name="booking_working_time_enabled"]' ).prop( 'checked', workingTime.enabled === 'On' );
487 get_form().find( '[data-wpbc-working-time-resource-id]' ).val( resourceId );
488 set_working_time_weekdays( 'booking_working_time_default', workingTime.default && workingTime.default.weekdays ? workingTime.default.weekdays : {} );
489 get_form().find( 'input[name="booking_working_time_resource_mode"][value="' + ( resourceSettings.mode || 'inherit' ) + '"]' ).prop( 'checked', true );
490 set_working_time_weekdays( 'booking_working_time_resource', resourceSettings.weekdays || ( workingTime.default ? workingTime.default.weekdays : {} ) );
491 refresh_working_time_panels();
492 }
493
494 function append_working_time_payload( payload ) {
495 var $form = get_form();
496 var defaultDays = [];
497 var resourceDays = [];
498 var defaultStart = {};
499 var defaultEnd = {};
500 var resourceStart = {};
501 var resourceEnd = {};
502
503 $form.find( '[data-wpbc-working-time-weekdays="booking_working_time_default"] .wpbc_ag_working_time_row' ).each( function () {
504 var $row = $( this );
505 var day = parseInt( $row.find( 'input[type="checkbox"]' ).val(), 10 );
506
507 defaultStart[ day ] = $row.find( '.wpbc_ag_working_time_start' ).val() || '09:00';
508 defaultEnd[ day ] = $row.find( '.wpbc_ag_working_time_end' ).val() || '18:00';
509 if ( $row.find( 'input[type="checkbox"]' ).prop( 'checked' ) ) {
510 defaultDays.push( day );
511 }
512 } );
513
514 $form.find( '[data-wpbc-working-time-weekdays="booking_working_time_resource"] .wpbc_ag_working_time_row' ).each( function () {
515 var $row = $( this );
516 var day = parseInt( $row.find( 'input[type="checkbox"]' ).val(), 10 );
517
518 resourceStart[ day ] = $row.find( '.wpbc_ag_working_time_start' ).val() || '09:00';
519 resourceEnd[ day ] = $row.find( '.wpbc_ag_working_time_end' ).val() || '18:00';
520 if ( $row.find( 'input[type="checkbox"]' ).prop( 'checked' ) ) {
521 resourceDays.push( day );
522 }
523 } );
524
525 payload.booking_working_time_enabled = $form.find( 'input[name="booking_working_time_enabled"]' ).prop( 'checked' ) ? 'On' : '';
526 payload.booking_working_time_resource_id = $form.find( '[data-wpbc-working-time-resource-id]' ).val() || $( '#wpbc_ag_resource_id' ).val() || '';
527 payload.booking_working_time_resource_mode = $form.find( 'input[name="booking_working_time_resource_mode"]:checked' ).val() || 'inherit';
528 payload.booking_working_time_default_days = defaultDays;
529 payload.booking_working_time_default_start = defaultStart;
530 payload.booking_working_time_default_end = defaultEnd;
531 payload.booking_working_time_resource_days = resourceDays;
532 payload.booking_working_time_resource_start = resourceStart;
533 payload.booking_working_time_resource_end = resourceEnd;
534 }
535
536 function update_wpbc_preview_params( settings ) {
537 if ( ! w._wpbc || typeof w._wpbc.set_other_param !== 'function' ) {
538 return;
539 }
540
541 w._wpbc.set_other_param( 'availability__week_days_unavailable', settings.weekdays.concat( [ 999 ] ) );
542 w._wpbc.set_other_param( 'availability__available_from_today', is_available_limit_available() ? ( settings.booking_available_days_num_from_today || '' ) : '' );
543 w._wpbc.set_other_param( 'availability__unavailable_from_today', settings.booking_unavailable_days_num_from_today || '0' );
544 }
545
546 function update_buffer_preview_note( settings ) {
547 var $notes = $( '[data-wpbc-ag-calendar-notes="1"]' ).first();
548 var $calendar = $( '[data-wpbc-ag-calendar-panel="1"]' ).first();
549 var $note = $notes.find( '.wpbc_ag_buffer_preview_note' );
550 var type = settings.booking_unavailable_extra_in_out || '';
551 var before_text = '';
552 var after_text = '';
553 var message = '';
554
555 if ( ! $notes.length || ! $calendar.length ) {
556 return;
557 }
558
559 if ( ! $note.length ) {
560 $note = $( '<div class="wpbc_ag_buffer_preview_note" aria-live="polite"></div>' );
561 $notes.append( $note );
562 }
563
564 if ( ! is_buffer_available() ) {
565 $calendar.removeClass( 'wpbc_ag_preview_buffer_active' );
566 $note.attr( 'hidden', 'hidden' );
567 return;
568 }
569
570 $calendar.toggleClass( 'wpbc_ag_preview_buffer_active', !! type );
571
572 if ( type === 'm' ) {
573 before_text = get_option_text( '[name="booking_unavailable_extra_minutes_in"]' ) || '-';
574 after_text = get_option_text( '[name="booking_unavailable_extra_minutes_out"]' ) || '-';
575 } else if ( type === 'd' ) {
576 before_text = get_option_text( '[name="booking_unavailable_extra_days_in"]' ) || '-';
577 after_text = get_option_text( '[name="booking_unavailable_extra_days_out"]' ) || '-';
578 }
579
580 if ( type ) {
581 message = '<strong>' + ( cfg.i18n && cfg.i18n.buffer_preview ? cfg.i18n.buffer_preview : 'Buffer preview' ) + ':</strong> ' +
582 ( cfg.i18n && cfg.i18n.before_booking ? cfg.i18n.before_booking : 'Before booking' ) + ' ' + before_text +
583 ' / ' + ( cfg.i18n && cfg.i18n.after_booking ? cfg.i18n.after_booking : 'After booking' ) + ' ' + after_text;
584 if ( $note.html() !== message ) {
585 $note.html( message );
586 }
587 if ( $note.attr( 'hidden' ) ) {
588 $note.removeAttr( 'hidden' );
589 }
590 } else {
591 message = cfg.i18n && cfg.i18n.no_buffer ? cfg.i18n.no_buffer : 'No booking buffer is selected.';
592 if ( $note.text() !== message ) {
593 $note.text( message );
594 }
595 if ( ! $note.attr( 'hidden' ) ) {
596 $note.attr( 'hidden', 'hidden' );
597 }
598 }
599 }
600
601 function apply_buffer_days_preview( settings ) {
602 var $calendar = $( '[data-wpbc-ag-calendar-panel="1"]' );
603 var before_days = get_days_value( settings.booking_unavailable_extra_days_in );
604 var after_days = get_days_value( settings.booking_unavailable_extra_days_out );
605 var date_cells = {};
606 var booked_dates = [];
607
608 if ( ! is_buffer_available() ) {
609 return;
610 }
611
612 if ( settings.booking_unavailable_extra_in_out !== 'd' || ( ! before_days && ! after_days ) ) {
613 return;
614 }
615
616 $calendar.find( '.datepick-days-cell' ).each( function () {
617 var $cell = $( this );
618 var sql_date = get_sql_date_from_cell( this );
619 var cell_date;
620
621 if ( ! sql_date ) {
622 return;
623 }
624
625 date_cells[ sql_date ] = $cell;
626
627 if ( $cell.hasClass( 'date_approved' ) || $cell.hasClass( 'date2approve' ) ) {
628 cell_date = date_from_sql( sql_date );
629 if ( cell_date ) {
630 booked_dates.push( cell_date );
631 }
632 }
633 } );
634
635 $.each( booked_dates, function ( index, booked_date ) {
636 var offset;
637 var target_sql_date;
638 var $target_cell;
639
640 for ( offset = before_days * -1; offset < 0; offset++ ) {
641 target_sql_date = date_to_sql( add_days( booked_date, offset ) );
642 $target_cell = date_cells[ target_sql_date ];
643 if ( $target_cell && ! $target_cell.hasClass( 'date_approved' ) && ! $target_cell.hasClass( 'date2approve' ) ) {
644 remember_preview_origin( $target_cell );
645 $target_cell.addClass( 'date_user_unavailable wpbc_ag_preview_unavailable wpbc_ag_preview_buffer_unavailable buffer_unavailable' );
646 $target_cell.attr( 'data-wpbc-ag-preview-reason', 'wpbc_ag_preview_buffer_unavailable' );
647 }
648 }
649
650 for ( offset = 1; offset <= after_days; offset++ ) {
651 target_sql_date = date_to_sql( add_days( booked_date, offset ) );
652 $target_cell = date_cells[ target_sql_date ];
653 if ( $target_cell && ! $target_cell.hasClass( 'date_approved' ) && ! $target_cell.hasClass( 'date2approve' ) ) {
654 remember_preview_origin( $target_cell );
655 $target_cell.addClass( 'date_user_unavailable wpbc_ag_preview_unavailable wpbc_ag_preview_buffer_unavailable buffer_unavailable' );
656 $target_cell.attr( 'data-wpbc-ag-preview-reason', 'wpbc_ag_preview_buffer_unavailable' );
657 }
658 }
659 } );
660 }
661
662 function remember_preview_origin( $cell ) {
663 if ( typeof $cell.attr( 'data-wpbc-ag-original-date-user-unavailable' ) === 'undefined' ) {
664 $cell.attr( 'data-wpbc-ag-original-date-user-unavailable', $cell.hasClass( 'date_user_unavailable' ) ? '1' : '0' );
665 }
666 }
667
668 function clear_preview_cell( $cell ) {
669 var had_date_user_unavailable = $cell.attr( 'data-wpbc-ag-original-date-user-unavailable' ) === '1';
670
671 $cell.removeClass( preview_unavailable_classes );
672 $cell.removeAttr( 'data-wpbc-ag-preview-reason' );
673 $cell.removeAttr( 'data-wpbc-ag-original-date-user-unavailable' );
674
675 if ( ! had_date_user_unavailable ) {
676 $cell.removeClass( 'date_user_unavailable' );
677 }
678 }
679
680 function apply_calendar_preview() {
681 var settings = collect_settings();
682 var today_date = get_real_today_date();
683 var available_limit = is_available_limit_available() ? parseInt( settings.booking_available_days_num_from_today || '0', 10 ) : 0;
684 var $calendar = $( '[data-wpbc-ag-calendar-panel="1"]' );
685
686 update_wpbc_preview_params( settings );
687 update_buffer_preview_note( settings );
688
689 $calendar.find( '.datepick-days-cell' ).each( function () {
690 var cell = this;
691 var $cell = $( cell );
692 var sql_date = get_sql_date_from_cell( cell );
693 var cell_date = date_from_sql( sql_date );
694 var make_unavailable = false;
695 var reason_class = '';
696 var previous_reason = $cell.attr( 'data-wpbc-ag-preview-reason' ) || '';
697 var had_general_preview = !! previous_reason || $cell.hasClass( 'wpbc_ag_preview_unavailable' ) || $cell.hasClass( 'weekday_unavailable' ) || $cell.hasClass( 'from_today_unavailable' ) || $cell.hasClass( 'limit_available_from_today' ) || $cell.hasClass( 'buffer_unavailable' );
698
699 if ( ! cell_date ) {
700 return;
701 }
702
703 if ( settings.weekdays.indexOf( cell_date.getDay() ) > -1 ) {
704 make_unavailable = true;
705 reason_class = 'wpbc_ag_preview_weekday_unavailable';
706 }
707
708 if ( unavailable_from_today_applies( cell_date, today_date, settings.booking_unavailable_days_num_from_today ) ) {
709 make_unavailable = true;
710 reason_class = 'wpbc_ag_preview_from_today_unavailable';
711 }
712
713 if ( available_limit > 0 && days_between( cell_date, today_date ) >= available_limit ) {
714 make_unavailable = true;
715 reason_class = 'wpbc_ag_preview_limit_available_from_today';
716 }
717
718 if ( make_unavailable ) {
719 if ( previous_reason !== reason_class ) {
720 if ( had_general_preview ) {
721 clear_preview_cell( $cell );
722 }
723 remember_preview_origin( $cell );
724 $cell.addClass( 'date_user_unavailable wpbc_ag_preview_unavailable ' + reason_class );
725 $cell.attr( 'data-wpbc-ag-preview-reason', reason_class );
726 }
727 } else if ( had_general_preview ) {
728 clear_preview_cell( $cell );
729 }
730 } );
731
732 apply_buffer_days_preview( settings );
733 }
734
735 function queue_preview_refresh() {
736 if ( preview_frame ) {
737 return;
738 }
739
740 if ( w.requestAnimationFrame ) {
741 preview_frame = w.requestAnimationFrame( function () {
742 preview_frame = 0;
743 apply_calendar_preview();
744 } );
745 } else {
746 preview_frame = w.setTimeout( function () {
747 preview_frame = 0;
748 apply_calendar_preview();
749 }, 0 );
750 }
751 }
752
753 function schedule_preview_refresh( delay ) {
754 clearTimeout( preview_timer );
755 delay = parseInt( delay, 10 ) || 0;
756
757 if ( delay > 0 ) {
758 preview_timer = setTimeout( queue_preview_refresh, delay );
759 return;
760 }
761
762 queue_preview_refresh();
763 }
764
765 function update_hints( hints ) {
766 if ( ! hints ) {
767 return;
768 }
769
770 if ( typeof hints.booking_unavailable_days_num_from_today__hint !== 'undefined' ) {
771 $( '[data-wpbc-ag-hint="booking_unavailable_days_num_from_today"]' ).html(
772 '<span class="wpbc_ag_hint_unavailable">' + $( '[data-wpbc-ag-hint="booking_unavailable_days_num_from_today"] .wpbc_ag_hint_unavailable' ).first().text() + '</span>' +
773 hints.booking_unavailable_days_num_from_today__hint
774 );
775 }
776
777 if ( typeof hints.booking_available_days_num_from_today__hint !== 'undefined' ) {
778 $( '[data-wpbc-ag-hint="booking_available_days_num_from_today"]' ).html(
779 '<span class="wpbc_ag_hint_available">' + $( '[data-wpbc-ag-hint="booking_available_days_num_from_today"] .wpbc_ag_hint_available' ).first().text() + '</span>' +
780 hints.booking_available_days_num_from_today__hint
781 );
782 }
783 }
784
785 function show_message( message, type, duration ) {
786 if ( typeof w.wpbc_admin_show_message === 'function' ) {
787 w.wpbc_admin_show_message( message, type || 'info', duration || 2000, false );
788 } else {
789 w.alert( message );
790 }
791 }
792
793 function set_busy( $button, busy ) {
794 var busy_text;
795
796 if ( ! $button || ! $button.length ) {
797 return;
798 }
799
800 if ( busy ) {
801 if ( ! $button.data( 'wpbc-ag-original-html' ) ) {
802 $button.data( 'wpbc-ag-original-html', $button.html() );
803 }
804 busy_text = $button.data( 'wpbc-u-busy-text' ) || ( cfg.i18n && cfg.i18n.saving ) || 'Saving...';
805 $button.addClass( 'wpbc_ag_is_saving' ).attr( 'aria-busy', 'true' ).html( '<i class="menu_icon icon-1x wpbc_icn_rotate_right wpbc_spin"></i><span class="in-button-text">&nbsp;&nbsp;' + busy_text + '</span>' );
806 } else {
807 $button.removeClass( 'wpbc_ag_is_saving' ).removeAttr( 'aria-busy' );
808 if ( $button.data( 'wpbc-ag-original-html' ) ) {
809 $button.html( $button.data( 'wpbc-ag-original-html' ) );
810 }
811 }
812 }
813
814 function replace_calendar_panel( html ) {
815 var $holder = $( '<div />' ).append( $.parseHTML( html, document, true ) );
816 var $new_panel = $holder.find( '[data-wpbc-ag-calendar-panel="1"]' ).first();
817 var $old_panel = $( '[data-wpbc-ag-calendar-panel="1"]' ).first();
818 var $scripts;
819
820 if ( ! $new_panel.length || ! $old_panel.length ) {
821 return;
822 }
823
824 $scripts = $new_panel.find( 'script' ).remove();
825 $old_panel.replaceWith( $new_panel );
826
827 $scripts.each( function () {
828 var code = this.text || this.textContent || this.innerHTML || '';
829 var src = this.src || '';
830
831 if ( src ) {
832 $.ajax( {
833 url: src,
834 dataType: 'script',
835 cache: true
836 } );
837 } else if ( code ) {
838 $.globalEval( code );
839 }
840 } );
841 }
842
843 function set_calendar_loading( is_loading ) {
844 var $calendar = $( '[data-wpbc-ag-calendar-panel="1"]' ).first();
845 var loading_text = cfg.i18n && cfg.i18n.loading ? cfg.i18n.loading : 'Loading';
846 var $loading;
847
848 if ( ! $calendar.length ) {
849 return;
850 }
851
852 if ( is_loading ) {
853 $loading = $calendar.find( '.wpbc_calendar_loading' ).first();
854 if ( ! $loading.length ) {
855 $loading = $(
856 '<div class="wpbc_calendar_loading wpbc_ag_calendar_loading">' +
857 '<span class="wpbc_icn_autorenew wpbc_spin"></span>&nbsp;&nbsp;' +
858 '<span></span>' +
859 '</div>'
860 );
861 $loading.find( 'span' ).last().text( loading_text + '...' );
862 $calendar.append( $loading );
863 }
864 $calendar.addClass( 'is-loading' ).attr( 'aria-busy', 'true' );
865 } else {
866 $calendar.removeClass( 'is-loading' ).removeAttr( 'aria-busy' );
867 $calendar.find( '.wpbc_calendar_loading' ).remove();
868 }
869 }
870
871 function get_preview_payload() {
872 return {
873 action: cfg.preview_action || 'WPBC_AJX_AVAILABILITY_GENERAL_PREVIEW',
874 nonce: cfg.nonce || '',
875 resource_id: $( '#wpbc_ag_resource_id' ).val() || '',
876 months_count: $( '#wpbc_ag_months_count' ).val() || ''
877 };
878 }
879
880 function load_calendar_preview() {
881 var $calendar = $( '[data-wpbc-ag-calendar-panel="1"]' ).first();
882 var current_preview_ajax;
883
884 if ( ! cfg.ajax_url ) {
885 show_message( ( cfg.i18n && cfg.i18n.preview_failed ) || 'Unable to refresh calendar preview.', 'error', 10000 );
886 return;
887 }
888
889 if ( preview_ajax && preview_ajax.readyState !== 4 ) {
890 preview_ajax.abort();
891 }
892
893 set_calendar_loading( true );
894
895 current_preview_ajax = $.ajax( {
896 url: cfg.ajax_url,
897 method: 'POST',
898 dataType: 'json',
899 data: get_preview_payload()
900 } );
901 preview_ajax = current_preview_ajax;
902
903 current_preview_ajax.done( function ( response ) {
904 if ( ! response || ! response.success || ! response.data || ! response.data.html ) {
905 show_message( ( response && response.data && response.data.message ) || ( cfg.i18n && cfg.i18n.preview_failed ) || 'Unable to refresh calendar preview.', 'error', 10000 );
906 return;
907 }
908
909 replace_calendar_panel( response.data.html );
910 $( '[data-wpbc-ag-page="1"]' ).attr( 'data-wpbc-ag-resource-id', response.data.resource_id || '' );
911 observe_calendar_changes();
912 schedule_preview_refresh();
913 setTimeout( schedule_preview_refresh, 600 );
914 } ).fail( function ( jq_xhr, text_status ) {
915 if ( text_status !== 'abort' ) {
916 show_message( ( cfg.i18n && cfg.i18n.preview_failed ) || 'Unable to refresh calendar preview.', 'error', 10000 );
917 }
918 } ).always( function () {
919 if ( preview_ajax === current_preview_ajax ) {
920 set_calendar_loading( false );
921 }
922 } );
923 }
924
925 function save_settings( button ) {
926 var $button = $( button );
927 var settings = collect_settings();
928 var payload = $.extend( {}, settings, {
929 action: cfg.action || 'WPBC_AJX_AVAILABILITY_GENERAL_SAVE',
930 nonce: cfg.nonce || '',
931 booking_unavailable_days: settings.weekdays
932 } );
933
934 append_working_time_payload( payload );
935
936 if ( ! cfg.ajax_url ) {
937 show_message( ( cfg.i18n && cfg.i18n.save_failed ) || 'Unable to save general availability settings.', 'error', 10000 );
938 return;
939 }
940
941 set_busy( $button, true );
942
943 $.ajax( {
944 url: cfg.ajax_url,
945 method: 'POST',
946 dataType: 'json',
947 data: payload
948 } ).done( function ( response ) {
949 if ( ! response || ! response.success ) {
950 show_message( ( response && response.data && response.data.message ) || ( cfg.i18n && cfg.i18n.save_failed ) || 'Unable to save general availability settings.', 'error', 10000 );
951 return;
952 }
953
954 if ( response.data && response.data.settings && response.data.settings.hints ) {
955 update_hints( response.data.settings.hints );
956 }
957 if ( response.data && response.data.settings ) {
958 cfg.settings = response.data.settings;
959 }
960
961 load_calendar_preview();
962 document.dispatchEvent( new CustomEvent( 'wpbc:availability-general:settings-saved', {
963 detail: {
964 settings: response.data && response.data.settings ? response.data.settings : {}
965 }
966 } ) );
967 show_message( ( response.data && response.data.message ) || ( cfg.i18n && cfg.i18n.saved ) || 'General availability settings updated.', 'success', 2000 );
968 } ).fail( function () {
969 show_message( ( cfg.i18n && cfg.i18n.save_failed ) || 'Unable to save general availability settings.', 'error', 10000 );
970 } ).always( function () {
971 set_busy( $button, false );
972 } );
973 }
974
975 function reset_settings( button ) {
976 var confirm_message = ( cfg.i18n && cfg.i18n.reset_confirm ) || 'Reset general availability settings to default values?';
977 var default_settings = cfg.default_settings || {
978 weekdays: [],
979 booking_unavailable_days_num_from_today: '0',
980 booking_available_days_num_from_today: '',
981 booking_unavailable_extra_in_out: '',
982 booking_unavailable_extra_minutes_in: '',
983 booking_unavailable_extra_minutes_out: '',
984 booking_unavailable_extra_days_in: '',
985 booking_unavailable_extra_days_out: '',
986 working_time: {}
987 };
988
989 if ( ! w.confirm( confirm_message ) ) {
990 return;
991 }
992
993 apply_settings_to_form( default_settings );
994 load_calendar_preview();
995 show_message( ( cfg.i18n && cfg.i18n.reset_applied ) || 'Default availability settings are ready for preview. Click Save Changes to apply them.', 'success', 4000 );
996 }
997
998 function observe_calendar_changes() {
999 var target = document.querySelector( '[data-wpbc-ag-calendar-panel="1"]' );
1000
1001 if ( ! target || ! w.MutationObserver ) {
1002 return;
1003 }
1004
1005 if ( observer ) {
1006 observer.disconnect();
1007 }
1008
1009 observer = new MutationObserver( schedule_preview_refresh );
1010 observer.observe( target, {
1011 childList: true,
1012 subtree: true
1013 } );
1014 }
1015
1016 $( document ).on( 'click', '.wpbc_ag_rightbar_tabs [role="tab"]', function () {
1017 switch_panel( $( this ) );
1018 } );
1019
1020 $( document ).on( 'click', '.wpbc_ag_rightbar_panels .group__header', function () {
1021 toggle_group( $( this ) );
1022 } );
1023
1024 $( document ).on( 'submit', '[data-wpbc-ag-preview-toolbar="1"]', function ( event ) {
1025 event.preventDefault();
1026 load_calendar_preview();
1027 } );
1028
1029 $( document ).on( 'change', '#wpbc_ag_resource_id, #wpbc_ag_months_count', load_calendar_preview );
1030
1031 $( document ).on( 'change', '#wpbc_ag_resource_id', function () {
1032 cfg.settings = cfg.settings || {};
1033 cfg.settings.working_time = get_working_time_settings_from_form();
1034 apply_working_time_settings_to_form( cfg.settings.working_time, $( this ).val() );
1035 } );
1036
1037 $( document ).on( 'input change', '[data-wpbc-ag-range-for]', function () {
1038 sync_select_from_range( this );
1039 schedule_preview_refresh();
1040 } );
1041
1042 $( document ).on( 'change', '[data-wpbc-ag-settings-form="1"] select', function () {
1043 sync_range_from_select( this );
1044 } );
1045
1046 $( document ).on( 'click', '[data-wpbc-ag-stepper]', function () {
1047 step_select_value( this );
1048 } );
1049
1050 $( document ).on( 'change', 'input[name="booking_unavailable_extra_in_out"]', function () {
1051 refresh_buffer_fields();
1052 schedule_preview_refresh();
1053 } );
1054
1055 $( document ).on( 'change', 'input[name="booking_working_time_enabled"]', refresh_working_time_panels );
1056
1057 $( document ).on( 'change', 'input[name="booking_working_time_resource_mode"]', refresh_working_time_panels );
1058
1059 $( document ).on( 'change', '[data-wpbc-ag-settings-form="1"] input, [data-wpbc-ag-settings-form="1"] select', schedule_preview_refresh );
1060
1061 $( document ).on( 'submit', '[data-wpbc-ag-settings-form="1"]', function ( event ) {
1062 event.preventDefault();
1063 save_settings( $( '[data-wpbc-ag-save="1"]' ).first() );
1064 } );
1065
1066 $( document ).on( 'click', '[data-wpbc-ag-save="1"]', function () {
1067 save_settings( this );
1068 } );
1069
1070 $( document ).on( 'click', '[data-wpbc-ag-reset="1"]', function () {
1071 reset_settings( this );
1072 } );
1073
1074 $( document ).ready( function () {
1075 apply_working_time_settings_to_form( ( cfg.settings && cfg.settings.working_time ) || ( cfg.default_settings && cfg.default_settings.working_time ) || {}, $( '#wpbc_ag_resource_id' ).val() );
1076 apply_open_section_from_url();
1077 refresh_buffer_fields();
1078 sync_all_ranges();
1079 observe_calendar_changes();
1080 schedule_preview_refresh();
1081 setTimeout( schedule_preview_refresh, 600 );
1082 } );
1083 }( jQuery, window ) );
1084