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 / js / wpbc_time-selector.js

wpbc_time-selector.js in Booking Calendar 11.9, at js/wpbc_time-selector.js

313 lines 10.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // FixIn: 8.7.11.10.
2 (function ( $ ){
3
4 /**
5 * Normalize native time options for the visual time-picker presentation.
6 *
7 * Empty values are select-box placeholders rather than bookable choices, so
8 * they must not become visual picker cards. If the native select currently
9 * points to a placeholder or a disabled option, select the first enabled real
10 * time to match the browser behavior of a picker-mode form exported without a
11 * placeholder.
12 *
13 * @param {Array<Object>} option_records Native option records.
14 * @return {Array<Object>} Normalized non-placeholder option records with at
15 * most one enabled selection.
16 */
17 function wpbc_timeselector_normalize_options( option_records ) {
18
19 var normalized_options = [];
20 var selected_option_index = -1;
21
22 $.each( Array.isArray( option_records ) ? option_records : [], function ( index, option_record ) {
23 var option_value = ( 'undefined' === typeof option_record.value || null === option_record.value ) ? '' : option_record.value;
24
25 if ( '' === String( option_value ).trim() ) {
26 return;
27 }
28
29 normalized_options.push( {
30 title : ( 'undefined' === typeof option_record.title || null === option_record.title ) ? '' : option_record.title,
31 value : option_value,
32 disabled: !! option_record.disabled,
33 selected: !! option_record.selected
34 } );
35
36 if (
37 -1 === selected_option_index
38 && ! option_record.disabled
39 && option_record.selected
40 ) {
41 selected_option_index = normalized_options.length - 1;
42 }
43 } );
44
45 if ( -1 === selected_option_index ) {
46 $.each( normalized_options, function ( index, option_record ) {
47 if ( ! option_record.disabled ) {
48 selected_option_index = index;
49 return false;
50 }
51 } );
52 }
53
54 $.each( normalized_options, function ( index, option_record ) {
55 option_record.selected = index === selected_option_index;
56 } );
57
58 return normalized_options;
59 }
60
61 $.fn.extend( {
62
63 wpbc_timeselector: function (){
64
65 var times_options = [];
66
67 this.each( function (){
68
69 var el = $( this );
70 var native_selected_option = el.find( 'option:selected' ).first();
71 var native_selected_value = native_selected_option.length ? String( native_selected_option.val() ) : '';
72 var automatic_selection_value = el.attr( 'data-wpbc-time-picker-auto-value' );
73 var has_explicit_native_selection = (
74 native_selected_option.length
75 && ! native_selected_option.is( ':disabled' )
76 && '' !== native_selected_value.trim()
77 && automatic_selection_value !== native_selected_value
78 );
79
80 // On new days click we are searching for old time items, and remove them from this booking form
81 if ( el.parent().find( '.wpbc_times_selector' ).length ) {
82 el.parent().find( '.wpbc_times_selector' ).remove();
83 }
84
85 el.find( 'option' ).each( function ( ind ){
86
87 times_options.push( {
88 title : jQuery( this ).text()
89 , value : jQuery( this ).val()
90 , disabled: jQuery( this ).is( ':disabled' )
91 , selected: jQuery( this ).is( ':selected' )
92 } );
93
94 } );
95
96 times_options = wpbc_timeselector_normalize_options( times_options );
97
98 $.each( times_options, function ( index, option_record ) {
99 if ( option_record.selected ) {
100 var selected_time_value = String( option_record.value );
101
102 el.val( selected_time_value );
103 if ( has_explicit_native_selection ) {
104 el.removeAttr( 'data-wpbc-time-picker-auto-value' );
105 } else {
106 el.attr( 'data-wpbc-time-picker-auto-value', selected_time_value );
107 }
108 return false;
109 }
110 } );
111
112 var times_options_element = $.fn.wpbc_timeselector.format( times_options );
113
114 el.after( times_options_element );
115
116 el.next('.wpbc_times_selector').find('div').not('.wpbc_time_picker_disabled').on( "click", function() {
117
118 // Get data value of clicked DIV time-slot
119 var selected_value = jQuery( this ).attr( 'data-value' );
120
121 // Remove previos selected class
122 jQuery( this ).parent( '.wpbc_times_selector' ).find( '.wpbc_time_selected' ).removeClass( 'wpbc_time_selected' );
123 // Set time item with selected Class
124 jQuery( this ).addClass('wpbc_time_selected');
125
126 el.find( 'option' ).prop( 'selected', false );
127 // Match the literal value without interpreting it as selector syntax.
128 el.find( 'option' ).filter( function (){
129 return selected_value === jQuery( this ).val();
130 } ).prop( 'selected', true );
131 el.removeAttr( 'data-wpbc-time-picker-auto-value' );
132
133 el.trigger( 'change' );
134 });
135
136 // Execute a function when the user presses a key (13 - Enter) on the keyboard. (FixIn: EAA)
137 el.next( '.wpbc_times_selector' ).find( 'div' ).not( '.wpbc_time_picker_disabled' ).on( "keypress", function (event) {
138 if ( 13 === event.which ) {
139 event.preventDefault();
140 console.log( jQuery( this ) );
141 jQuery( this ).trigger( 'click' );
142 }
143 } );
144
145 el.hide();
146
147 times_options = [];
148 } );
149
150 return this; // Chain
151 }
152 } );
153
154 /**
155 * Build the visual time-slot selector from native option data.
156 *
157 * Values and labels can originate in saved form configuration or modified
158 * DOM state. Creating elements and assigning text/attributes separately
159 * prevents either value from becoming executable markup.
160 *
161 * @param {Array<Object>} el_arr Time-slot option records.
162 * @return {jQuery} Detached, safely populated time-slot selector.
163 */
164 $.fn.wpbc_timeselector.format = function ( el_arr ) {
165
166 var times_selector = jQuery( document.createElement( 'div' ) ).addClass( 'wpbc_times_selector' );
167 var has_available_times = false;
168 var normalized_options = wpbc_timeselector_normalize_options( el_arr );
169
170 $.each( normalized_options, function (index, el_item){
171
172 if ( !el_item.disabled ){
173 var time_option_value = ( 'undefined' === typeof el_item.value || null === el_item.value ) ? '' : el_item.value;
174 var time_option_title = ( 'undefined' === typeof el_item.title || null === el_item.title ) ? '' : el_item.title;
175 var time_option = jQuery( document.createElement( 'div' ) )
176 .attr( 'data-value', String( time_option_value ) )
177 .attr( 'tabindex', '0' )
178 .text( String( time_option_title ) );
179
180 if ( el_item.selected ){
181 time_option.addClass( 'wpbc_time_selected' );
182 }
183
184 times_selector.append( time_option );
185 has_available_times = true;
186 } else {
187 // Uncomment row bellow to Show booked time slots as unavailable RED slots // FixIn: 9.9.0.2.
188 // Add a disabled element through the same DOM construction path when this feature is enabled.
189 }
190
191 } );
192
193 if ( ! has_available_times ){
194 times_selector.append(
195 jQuery( document.createElement( 'span' ) )
196 .addClass( 'wpbc_no_time_pickers' )
197 .text( 'No available times' )
198 );
199 }
200
201 return times_selector;
202 };
203
204
205 })( jQuery );
206
207
208 /**
209 * Remove visual time pickers and restore native select-box placeholders.
210 *
211 * Only values automatically chosen by the visual picker are restored. An
212 * explicit customer choice remains selected when a live settings preview is
213 * switched back to Select box mode.
214 *
215 * @param {HTMLElement|Document|jQuery|null} context Optional preview boundary.
216 * @return {void}
217 */
218 function wpbc_hook__destroy_timeselector( context ){
219
220 var selector = 'select[name^="rangetime"], select[name^="starttime"], select[name^="endtime"], select[name^="durationtime"]';
221 var scope = context ? jQuery( context ) : jQuery( document );
222
223 scope.find( '.wpbc_times_selector' ).remove();
224 scope.find( selector ).each( function (){
225 var select_element = jQuery( this );
226 var current_value = select_element.val();
227 var automatic_value = select_element.attr( 'data-wpbc-time-picker-auto-value' );
228
229 current_value = ( 'undefined' === typeof current_value || null === current_value ) ? '' : String( current_value );
230 if ( 'undefined' !== typeof automatic_value && automatic_value === current_value ) {
231 var placeholder_option = select_element.find( 'option' ).filter( function (){
232 var option_value = jQuery( this ).val();
233
234 return 'undefined' === typeof option_value || null === option_value || '' === String( option_value ).trim();
235 } ).first();
236
237 if ( placeholder_option.length ) {
238 select_element.val( placeholder_option.val() );
239 }
240 }
241
242 select_element.removeAttr( 'data-wpbc-time-picker-auto-value' ).show();
243 } );
244 }
245
246
247 /**
248 * Initialize the visual time-slot selectors when the WPBC runtime is ready.
249 *
250 * The readiness check prevents a JavaScript error when a third-party optimizer
251 * delays wpbc_all.js, which creates window._wpbc, beyond document ready.
252 *
253 * @return {boolean} True when initialization is complete or not required;
254 * otherwise false when the WPBC runtime is not ready yet.
255 */
256 function wpbc_hook__init_timeselector(){
257
258 if (
259 ( 'object' !== typeof window._wpbc )
260 || ( 'function' !== typeof window._wpbc.get_other_param )
261 ) {
262 return false;
263 }
264
265 if ( true !== window._wpbc.get_other_param( 'is_enabled_booking_timeslot_picker' ) ) {
266 return true;
267 }
268
269 // Load after page loaded
270 jQuery( 'select[name^="rangetime"]' ).wpbc_timeselector();
271 jQuery( 'select[name^="starttime"]' ).wpbc_timeselector();
272 jQuery( 'select[name^="endtime"]' ).wpbc_timeselector();
273 jQuery( 'select[name^="durationtime"]' ).wpbc_timeselector();
274
275 // This hook loading after each day selection // FixIn: 8.7.11.9.
276 jQuery( ".booking_form_div" ).on( 'wpbc_hook_timeslots_disabled', function ( event, bk_type, all_dates ){
277 jQuery( '#booking_form_div' + bk_type + ' select[name^="rangetime"]' ).wpbc_timeselector();
278 jQuery( '#booking_form_div' + bk_type + ' select[name^="starttime"]' ).wpbc_timeselector();
279 jQuery( '#booking_form_div' + bk_type + ' select[name^="endtime"]' ).wpbc_timeselector();
280 jQuery( '#booking_form_div' + bk_type + ' select[name^="durationtime"]' ).wpbc_timeselector();
281 } );
282
283 return true;
284 }
285
286
287 /**
288 * Initialize the time selector now or after the WPBC core signals readiness.
289 *
290 * @return {void}
291 */
292 function wpbc_init_timeselector_when_wpbc_ready(){
293
294 if ( wpbc_hook__init_timeselector() ) {
295 return;
296 }
297
298 var wpbc_timeselector_ready_handler = function (){
299 if ( wpbc_hook__init_timeselector() ) {
300 document.removeEventListener( 'wpbc-ready', wpbc_timeselector_ready_handler );
301 }
302 };
303
304 document.addEventListener( 'wpbc-ready', wpbc_timeselector_ready_handler );
305 }
306
307
308 jQuery(document).ready(function(){
309 // setTimeout( function ( ) { // Need to have some delay for loading of all times in Garbage
310 wpbc_init_timeselector_when_wpbc_ready();
311 // }, 1000 );
312 });
313