PluginProbe
Booking Calendar / 11.6
Booking Calendar v11.6
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-appointment / _src / add_appointment_page.js

add_appointment_page.js in Booking Calendar 11.6, at includes/page-add-appointment/_src/add_appointment_page.js

262 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /** Add Appointment administrator inspector and non-submitting helper tools. */
2 ( function ( $ ) {
3 'use strict';
4
5 var summary_timer = 0;
6 var labels = window.wpbc_add_appointment_page_config || {};
7
8 /** Apply the administrator page context before any Provider calendar loads. */
9 function apply_booking_context() {
10 if ( 'undefined' === typeof window._wpbc ) {
11 return;
12 }
13
14 window._wpbc.set_other_param( 'this_page_booking_hash', '' );
15 window._wpbc.set_other_param( 'this_page_allow_past', labels.allowPast ? 1 : 0 );
16 window._wpbc.set_other_param( 'this_page_allow_past_arr', labels.allowPastDateArr || [] );
17 }
18
19 /** Switch one shared right-sidebar panel. */
20 function switch_right_panel( $tab ) {
21 var panel_id = $tab.attr( 'aria-controls' );
22 var $tabs = $tab.closest( '.wpbc_add_appointment__rightbar_tabs' ).find( '[role="tab"]' );
23 var $panels = $( '.wpbc_add_appointment__rightbar' ).find( '[role="tabpanel"]' );
24
25 $tabs.attr( 'aria-selected', 'false' );
26 $tab.attr( 'aria-selected', 'true' );
27 $panels.attr( { hidden: true, 'aria-hidden': 'true' } );
28 $( '#' + panel_id ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
29 }
30
31 /** Return trimmed visible text from the first matching element. */
32 function get_text( $root, selector ) {
33 return String( $root.find( selector ).first().text() || '' ).replace( /\s+/g, ' ' ).trim();
34 }
35
36 /** Return the display value of one native Booking Form field. */
37 function get_field_value( $field ) {
38 var value;
39
40 if ( ! $field.length ) {
41 return '';
42 }
43 if ( $field.is( 'select' ) ) {
44 value = $field.find( 'option:selected' ).text();
45 } else {
46 value = $field.val();
47 }
48
49 return String( value || '' ).replace( /\s+/g, ' ' ).trim();
50 }
51
52 /** Update one summary value and its empty-state presentation. */
53 function set_summary_value( key, value ) {
54 var $target = $( '[data-wpbc-add-appointment-summary="' + key + '"]' );
55 var is_empty = '' === String( value || '' ).trim();
56
57 $target.text( is_empty ? ( labels.emptyLabel || 'Not selected' ) : value );
58 $target.toggleClass( 'is-empty', is_empty );
59 }
60
61 /**
62 * Expand one Settings inspector group through the shared collapsible API.
63 *
64 * @param {string} group_name Group data key.
65 * @param {string} focus_selector Optional control to focus after expansion.
66 * @return {void}
67 */
68 function open_inspector_group( group_name, focus_selector ) {
69 var $group = $( '.wpbc_add_appointment__inspector_overview .wpbc_ui__collapsible_group[data-group="' + group_name + '"]' ).first();
70 var root;
71 var api;
72
73 if ( ! $group.length ) {
74 return;
75 }
76
77 root = $group.closest( '.wpbc_collapsible' ).get( 0 );
78 api = root && root.__wpbc_collapsible_instance;
79
80 if ( api && 'function' === typeof api.expand ) {
81 api.expand( $group.get( 0 ) );
82 } else {
83 $group.siblings( '.wpbc_ui__collapsible_group' ).each( function () {
84 var $sibling = $( this );
85 $sibling.removeClass( 'is-open' );
86 $sibling.children( '.group__header' ).attr( 'aria-expanded', 'false' );
87 $sibling.children( '.group__fields' ).attr( { hidden: true, 'aria-hidden': 'true' } );
88 } );
89 $group.addClass( 'is-open' );
90 $group.children( '.group__header' ).attr( 'aria-expanded', 'true' );
91 $group.children( '.group__fields' ).removeAttr( 'hidden' ).attr( 'aria-hidden', 'false' );
92 }
93
94 window.requestAnimationFrame( function () {
95 $group.get( 0 ).scrollIntoView( { behavior: 'smooth', block: 'start' } );
96 if ( focus_selector ) {
97 window.setTimeout( function () {
98 $( focus_selector ).first().trigger( 'focus' );
99 }, 250 );
100 }
101 } );
102 }
103
104 /** Format the effective before/after Service buffers. */
105 function get_buffer_summary( $source ) {
106 var before = $source.attr( 'data-buffer-before' );
107 var after = $source.attr( 'data-buffer-after' );
108
109 if ( 'undefined' === typeof before ) {
110 before = $source.attr( 'data-summary-buffer-before' );
111 after = $source.attr( 'data-summary-buffer-after' );
112 }
113 if ( 'undefined' === typeof before || 'undefined' === typeof after ) {
114 return '';
115 }
116
117 return String( before ) + ' / ' + String( after ) + ' ' + ( labels.minutesLabel || 'min' );
118 }
119
120 /** Read the most useful customer identity from the loaded Booking Form. */
121 function get_customer_summary( $form ) {
122 var first = get_field_value( $form.find( '[name^="firstname"]' ).first() );
123 var last = get_field_value( $form.find( '[name^="secondname"], [name^="lastname"]' ).first() );
124 var email = get_field_value( $form.find( '[name^="email"]' ).first() );
125 var name = String( first + ' ' + last ).trim();
126
127 return name || email;
128 }
129
130 /** Mirror live Appointment and native Booking Form values into the inspector. */
131 function refresh_summary() {
132 var $root = $( '.wpbc_add_appointment__canvas .wpbc_booking_appointment' ).first();
133 var $native = $root.find( '.wpbc_booking_appointment__native_form' ).first();
134 var $form = $native.find( 'form' ).first();
135 var $service = $root.find( 'input[name="wpbc_appointment_service"]:checked' ).closest( '.wpbc_booking_appointment__choice' );
136 var $provider = $root.find( 'input[name="wpbc_appointment_provider"]:checked' ).closest( '.wpbc_booking_appointment__choice' );
137 var $selected = $root.find( '.wpbc_booking_appointment__selected' ).first();
138 var $detail_source = $provider.length ? $provider : ( $service.length ? $service : $selected );
139 var stage = $root.attr( 'data-appointment-stage' ) || 'service';
140 var step = get_text( $root, '.wpbc_booking_appointment__progress_step.is-active .wpbc_booking_appointment__progress_label' );
141 var service = $service.attr( 'data-summary-service' ) || $selected.attr( 'data-summary-service' ) || '';
142 var provider = $provider.attr( 'data-summary-provider' ) || '';
143 var duration = $detail_source.attr( 'data-summary-duration' ) || '';
144 var price = $detail_source.attr( 'data-summary-price' ) || '';
145
146 if ( $native.length ) {
147 service = $native.attr( 'data-service-title' ) || service;
148 provider = $native.attr( 'data-provider-title' ) || provider;
149 duration = $native.attr( 'data-duration-label' ) || duration;
150 price = $native.attr( 'data-service-cost-label' ) || price;
151 $detail_source = $native;
152 }
153
154 set_summary_value( 'step', step || stage );
155 set_summary_value( 'service', service );
156 set_summary_value( 'provider', provider );
157 set_summary_value( 'duration', duration );
158 set_summary_value( 'buffers', get_buffer_summary( $detail_source ) );
159 set_summary_value( 'price', price );
160 set_summary_value( 'date', get_field_value( $form.find( '[id^="date_booking"]' ).first() ) );
161 set_summary_value( 'time', get_field_value( $form.find( '[name^="starttime"]' ).first() ) );
162 set_summary_value( 'customer', get_customer_summary( $form ) );
163 set_summary_value( 'form', $native.attr( 'data-form-slug' ) || '' );
164 set_summary_value( 'emails', $( '#is_send_email_for_pending' ).is( ':checked' ) ? ( labels.enabledLabel || 'Enabled' ) : ( labels.disabledLabel || 'Disabled' ) );
165 $( '[data-wpbc-add-appointment-start-over]' ).prop( 'hidden', 'service' === stage );
166 $( '[data-wpbc-add-appointment-autofill]' ).prop( 'disabled', ! $form.length );
167 }
168
169 /** Debounce summary work during large AJAX Booking Form DOM insertions. */
170 function schedule_summary_refresh() {
171 window.clearTimeout( summary_timer );
172 summary_timer = window.setTimeout( refresh_summary, 20 );
173 }
174
175 /** Fill sample customer fields in the current form without submitting it. */
176 function auto_fill_booking_form() {
177 var $form = $( '.wpbc_add_appointment__canvas .wpbc_booking_appointment__native_form form' ).first();
178
179 if ( ! $form.length ) {
180 return;
181 }
182
183 $form.find( 'input, textarea, select' ).each( function () {
184 var $field = $( this );
185 var name = String( $field.attr( 'name' ) || '' ).toLowerCase();
186 var type = String( $field.attr( 'type' ) || '' ).toLowerCase();
187 var ignored = /date_booking|starttime|endtime|durationtime|rangetime|captcha|coupon|service_id|appointment_/.test( name );
188 var value = '';
189
190 if ( ignored || $field.is( ':disabled' ) || 'hidden' === type || 'button' === type || 'submit' === type || 'radio' === type ) {
191 return;
192 }
193 if ( 'checkbox' === type ) {
194 if ( $field.prop( 'required' ) ) {
195 $field.prop( 'checked', true ).trigger( 'change' );
196 }
197 return;
198 }
199 if ( $field.is( 'select' ) ) {
200 if ( ! $field.val() ) {
201 var $option = $field.find( 'option:not(:disabled)' ).filter( function () {
202 return '' !== String( $( this ).val() || '' );
203 } ).first();
204 if ( $option.length ) {
205 $field.val( $option.val() ).trigger( 'change' );
206 }
207 }
208 return;
209 }
210 if ( /^firstname/.test( name ) ) {
211 value = 'John';
212 } else if ( /^(secondname|lastname)/.test( name ) ) {
213 value = 'Smith';
214 } else if ( /^email/.test( name ) || 'email' === type ) {
215 value = '[email protected]';
216 } else if ( /^phone/.test( name ) || 'tel' === type ) {
217 value = '0000000000';
218 } else if ( $field.is( 'textarea' ) ) {
219 value = '---';
220 }
221
222 if ( value && ! $field.val() ) {
223 $field.val( value ).trigger( 'input' ).trigger( 'change' );
224 }
225 } );
226
227 schedule_summary_refresh();
228 }
229
230 $( document ).on( 'click', '.wpbc_add_appointment__rightbar_tabs [role="tab"]', function ( event ) {
231 event.preventDefault();
232 switch_right_panel( $( this ) );
233 } );
234
235 $( document ).on( 'click', '[data-wpbc-add-appointment-start-over]', function () {
236 var $action = $( '.wpbc_add_appointment__canvas [data-wpbc-appointment-action="start-over"]' ).first();
237 if ( ! $action.length ) {
238 $action = $( '.wpbc_add_appointment__canvas [data-appointment-back="service"]' ).first();
239 }
240 if ( $action.length ) {
241 $action.trigger( 'click' );
242 }
243 } );
244
245 $( document ).on( 'click', '[data-wpbc-add-appointment-open-group]', function ( event ) {
246 event.preventDefault();
247 open_inspector_group( $( this ).attr( 'data-wpbc-add-appointment-open-group' ), $( this ).attr( 'data-wpbc-add-appointment-focus' ) || '' );
248 } );
249
250 $( document ).on( 'click', '[data-wpbc-add-appointment-autofill]', auto_fill_booking_form );
251 $( document ).on( 'input change wpbc_booking_date_or_option_selected', '.wpbc_add_appointment__canvas, #is_send_email_for_pending', schedule_summary_refresh );
252
253 $( function () {
254 var stage = document.querySelector( '.wpbc_add_appointment__canvas .wpbc_booking_appointment__stage' );
255 apply_booking_context();
256 refresh_summary();
257 if ( stage && window.MutationObserver ) {
258 new MutationObserver( schedule_summary_refresh ).observe( stage, { childList: true, subtree: true } );
259 }
260 } );
261 } )( jQuery );
262