PluginProbe
Booking Calendar / 11.2
Booking Calendar v11.2
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-form-builder / field-packs / time-range / field-rangetime-wptpl.php

field-rangetime-wptpl.php in Booking Calendar 11.2, at includes/page-form-builder/field-packs/time-range/field-rangetime-wptpl.php

672 lines 34.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPBC BFB Pack: Range Time (time-slots).
4 *
5 * - Adds a "rangetime" field that renders dropdown options like: [selectbox rangetime "Label@@HH:MM - HH:MM" ...]
6 * - Labels can be AM/PM or 24h; values are always strict 24h ranges.
7 * - Inspector:
8 * - AM/PM </> 24H switch (radio)
9 * - Generator: Start/End + Duration: AM/PM uses native <input type="time">, 24H uses iMask.js
10 * - Options editor with rows that mirror the chosen format
11 * - Requires iMask.js (already loaded on the Builder page).
12 *
13 * @package Booking Calendar
14 * @author wpdevelop
15 * @since 11.0.0
16 * @modified 31.10.2025 13:54
17 * @version 1.7.1
18 */
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit;
22 }
23
24 /**
25 * Register the "rangetime" field pack.
26 *
27 * @param array $packs Packs map.
28 *
29 * @return array
30 */
31 /**
32 * Register the "rangetime" field pack.
33 *
34 * @param array $packs Packs map.
35 * @return array
36 */
37 function wpbc_bfb_register_field_packs__field_rangetime_wptpl( $packs ) {
38 $packs['rangetime'] = array(
39 'kind' => 'field',
40 'type' => 'rangetime',
41 'label' => __( 'Time slots', 'booking' ),
42 'icon' => 'wpbc-bi-clock',
43 'usage_key' => 'rangetime',
44
45 // Schema defines defaults and coercion.
46 'schema' => array(
47 'props' => array(
48 'label' => array( 'type' => 'string', 'default' => __( 'Time', 'booking' ) ),
49 'name' => array( 'type' => 'string', 'default' => 'rangetime' ),
50 'html_id' => array( 'type' => 'string', 'default' => '' ),
51 'required' => array( 'type' => 'boolean', 'default' => true ),
52 'multiple' => array( 'type' => 'boolean', 'default' => false ),
53 'size' => array( 'type' => 'number', 'default' => null, 'min' => 2, 'max' => 20 ),
54 'cssclass' => array( 'type' => 'string', 'default' => '' ),
55 'help' => array( 'type' => 'string', 'default' => '' ),
56 'default_value' => array( 'type' => 'string', 'default' => '' ),
57 'placeholder' => array( 'type' => 'string', 'default' => '--- ' . __( 'Select time', 'booking' ) . ' ---' ),
58 'value_differs' => array( 'type' => 'boolean', 'default' => true ),
59
60 // Options: label (string), value (string "HH:MM - HH:MM"), selected (bool).
61 'options' => array(
62 'type' => 'array',
63 'default' => array(
64 array( 'label' => '10:00 AM - 12:00 PM', 'value' => '10:00 - 12:00', 'selected' => false ),
65 array( 'label' => '12:00 PM - 02:00 PM', 'value' => '12:00 - 14:00', 'selected' => false ),
66 array( 'label' => '02:00 PM - 04:00 PM', 'value' => '14:00 - 16:00', 'selected' => false ),
67 array( 'label' => '04:00 PM - 06:00 PM', 'value' => '16:00 - 18:00', 'selected' => false ),
68 array( 'label' => '06:00 PM - 08:00 PM', 'value' => '18:00 - 20:00', 'selected' => false ),
69 ),
70 ),
71
72 // Generator controls:.
73 'gen_label_fmt' => array( 'type' => 'string', 'default' => 'ampm' ), // 'ampm' | '24h'
74 'gen_start_24h' => array( 'type' => 'string', 'default' => '09:00' ),
75 'gen_end_24h' => array( 'type' => 'string', 'default' => '18:00' ),
76 'gen_start_ampm_t' => array( 'type' => 'string', 'default' => '09:00' ),
77 // <input type=time> expects "HH:MM"
78 'gen_end_ampm_t' => array( 'type' => 'string', 'default' => '18:00' ),
79 'gen_step_h' => array( 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 12 ),
80 'gen_step_m' => array( 'type' => 'number', 'default' => 30, 'min' => 0, 'max' => 59 ),
81
82 'min_width' => array( 'type' => 'string', 'default' => '240px' ),
83 ),
84 ),
85
86 'templates_printer' => 'wpbc_bfb_field_rangetime_wptpl_print_templates',
87 );
88
89 return $packs;
90 }
91 add_filter( 'wpbc_bfb_register_field_packs', 'wpbc_bfb_register_field_packs__field_rangetime_wptpl' );
92
93
94 /**
95 * Enqueue the Range Time pack JS.
96 *
97 * @param string $page Current admin page slug.
98 * @return void
99 */
100 function wpbc_bfb_enqueue__field_rangetime_wptpl_js( $page ) {
101
102 // iMask.js is already enqueued on this page.
103 wp_enqueue_script( 'wpbc-bfb_field_rangetime_wptpl', wpbc_plugin_url( '/includes/page-form-builder/field-packs/time-range/_out/field-rangetime-wptpl.js' ), array( 'wp-util', 'wpbc-bfb', 'wpbc-bfb-time-utils' ), WP_BK_VERSION_NUM, true );
104 }
105 add_action( 'wpbc_enqueue_js_field_pack', 'wpbc_bfb_enqueue__field_rangetime_wptpl_js', 10, 1 );
106
107
108 /**
109 * Palette item (optional).
110 *
111 * @param string $group Group key.
112 * @param string $position Position.
113 * @return void
114 */
115 function wpbc_bfb_palette_register_items__rangetime_wptpl( $group, $position ) {
116 if ( 'times' !== $group || 'bottom' !== $position ) {
117 return;
118 }
119 $default_options = array(
120 array( 'label' => '10:00 AM - 12:00 PM', 'value' => '10:00 - 12:00', 'selected' => false ),
121 array( 'label' => '12:00 PM - 02:00 PM', 'value' => '12:00 - 14:00', 'selected' => false ),
122 array( 'label' => '02:00 PM - 04:00 PM', 'value' => '14:00 - 16:00', 'selected' => false ),
123 array( 'label' => '04:00 PM - 06:00 PM', 'value' => '16:00 - 18:00', 'selected' => false ),
124 array( 'label' => '06:00 PM - 08:00 PM', 'value' => '18:00 - 20:00', 'selected' => false ),
125 );
126 ?>
127 <li class="wpbc_bfb__field"
128 data-id="rangetime"
129 data-type="rangetime"
130 data-usage_key="rangetime"
131 data-usagenumber="1"
132 data-min_width="240px"
133 data-label="<?php echo esc_attr( __( 'Time slots', 'booking' ) ); ?>"
134 data-name="rangetime"
135 data-required="true"
136 data-autoname="0"
137 data-fresh="0"
138 data-name_user_touched="1"
139 data-options="<?php echo esc_attr( wp_json_encode( $default_options ) ); ?>">
140 <i class="menu_icon icon-1x wpbc_icn_access_time"></i>
141 <span class="wpbc_bfb__field-label"><?php echo esc_html( __( 'Time slots', 'booking' ) ); ?></span>
142 <span class="wpbc_bfb__field-type">rangetime</span>
143 </li>
144 <?php
145 }
146 add_action( 'wpbc_bfb_palette_register_items', 'wpbc_bfb_palette_register_items__rangetime_wptpl', 10, 2 );
147
148
149
150 /**
151 * Print wp.template() blocks (Preview + Inspector).
152 *
153 * @param string $page Builder page slug.
154 * @return void
155 */
156 function wpbc_bfb_field_rangetime_wptpl_print_templates( $page ) {
157
158 if ( WPBC_BFB_BUILDER_PAGE_SLUG !== $page ) {
159 return;
160 }
161
162 ?>
163 <script type="text/html" id="tmpl-wpbc-bfb-field-rangetime">
164 <span class="wpbc_bfb__noaction wpbc_bfb__no-drag-zone" inert="" style="min-width: {{ data.min_width || '240px' }}">
165 <# var is_req = ( true === data.required || 'true' === data.required || 1 === data.required || '1' === data.required ); #>
166 <# var is_mul = ( true === data.multiple || 'true' === data.multiple || 1 === data.multiple || '1' === data.multiple ); #>
167
168 <# if ( data.label && data.label !== '' ) { #>
169 <label class="wpbc_bfb__field-label" <# if ( data.html_id ) { #> for="{{ data.html_id }}" <# } #>>
170 {{ data.label }} <# if ( is_req ) { #><span aria-hidden="true">*</span><# } #>
171 </label>
172 <# } #>
173
174 <span class="wpbc_wrap_text wpdev-form-control-wrap">
175 <select
176 class="wpbc_bfb__preview-input wpbc_bfb__preview-select wpbc_bfb__preview-rangetime wpbc_bfb__preview-timepicker {{ data.cssclass || '' }}"
177 name="{{ (data.name || data.id || 'rangetime') + ( is_mul ? '[]' : '' ) }}"
178 tabindex="-1" aria-disabled="true"
179 <# if ( data.html_id ) { #> id="{{ data.html_id }}" <# } #>
180 <# if ( is_req ) { #> required aria-required="true" <# } #>
181 <# if ( is_mul ) { #> multiple <# } #>
182 <# if ( is_mul && data.size && isFinite( Number( data.size ) ) ) { #> size="{{ Number( data.size ) }}" <# } #>
183 >
184 <#
185 var has_marked = Array.isArray( data.options ) && data.options.some( function(o){
186 return !! o && ( true === o.selected || 'true' === o.selected || 1 === o.selected || '1' === o.selected );
187 } );
188 var has_text_default = ( ! is_mul ) && ( (data.default_value != null) && String( data.default_value ).trim() !== '' );
189 var has_any_default = has_marked || has_text_default;
190
191 var selected_set = {};
192 if ( has_marked ) {
193 ( data.options || [] ).forEach( function(o){
194 if ( o && ( true === o.selected || 'true' === o.selected || 1 === o.selected || '1' === o.selected ) ) {
195 selected_set[ String( o.value || '' ) ] = true;
196 }
197 } );
198 } else if ( is_mul ) {
199 String( data.default_value || '' ).split( /\s*,\s*/ ).filter( function(s){ return s.length; } )
200 .forEach( function(v){ selected_set[ v ] = true; } );
201 } else if ( has_text_default ) {
202 selected_set[ String( data.default_value ) ] = true;
203 }
204 #>
205
206 <# if ( ! is_mul && data.placeholder && ! has_any_default ) { #>
207 <option value="" selected="selected" disabled="disabled">{{ data.placeholder }}</option>
208 <# } #>
209
210 <#
211 var _opts = Array.isArray( data.options ) ? data.options
212 : ( function(o){ var a=[],k; for ( k in (o||{}) ){ if ( Object.prototype.hasOwnProperty.call(o,k) ){ a.push( o[k] ); } } return a; } )( data.options );
213 _opts.forEach( function( opt ){
214 if ( ! opt ) { return; }
215 var _val = String( opt.value || '' );
216 var _lbl = String( opt.label || '' );
217 var _sel = !! selected_set[ _val ];
218 #>
219 <option value="{{ _val }}" <# if ( _sel ) { #> selected <# } #> >{{ _lbl }}</option>
220 <# }); #>
221 </select>
222 </span>
223
224 <# if ( data.help ) { #>
225 <div class="wpbc_bfb__help">{{ data.help }}</div>
226 <# } #>
227 </span>
228 </script>
229
230 <script type="text/html" id="tmpl-wpbc-bfb-inspector-rangetime">
231 <style type="text/css">
232 .wpbc_admin .wpbc_ui_el__vert_right_bar__wrapper:has(.wpbc_bfb__inspector_timepicker) {
233 --wpbc_ui_left_vert_nav__width_max: Min(580px, 100%);
234 }
235 </style>
236 <div class="wpbc_bfb__inspector_rangetime wpbc_bfb__inspector_timepicker" data-type="rangetime"
237 data-i18n-add="<?php echo esc_attr__( 'Add New', 'booking' ); ?>"
238 data-i18n-duplicate="<?php echo esc_attr__( 'Duplicate', 'booking' ); ?>"
239 data-i18n-remove="<?php echo esc_attr__( 'Remove', 'booking' ); ?>"
240 data-i18n-default="<?php echo esc_attr__( 'Default', 'booking' ); ?>"
241 data-i18n-reorder="<?php echo esc_attr__( 'Drag to reorder', 'booking' ); ?>"
242 data-i18n-rowlabel="<?php echo esc_attr__( 'Label (e.g. 10:00 AM - 10:30 AM)', 'booking' ); ?>"
243 >
244 <div class="wpbc_bfb__inspector__head">
245 <div class="header_container">
246 <div class="header_title_content">
247 <h3 class="title"><?php echo esc_html__( 'Time slots', 'booking' ); ?></h3>
248 <div class="desc"><?php echo esc_html__( 'Use the "Generate time slots" form to quickly create a list of time slots.', 'booking' ); ?></div>
249 </div>
250 <div class="actions wpbc_ajx_toolbar wpbc_no_borders">
251 <div class="ui_container ui_container_small">
252 <div class="ui_group">
253 <div class="ui_element">
254 <button type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button" data-action="deselect" aria-label="<?php echo esc_attr__( 'Deselect', 'booking' ); ?>">
255 <i class="menu_icon icon-1x wpbc_icn_remove_done"></i>
256 </button>
257 <button type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button" data-action="scrollto" aria-label="<?php echo esc_attr__( 'Scroll to field', 'booking' ); ?>">
258 <i class="menu_icon icon-1x wpbc_icn_ads_click filter_center_focus"></i>
259 </button>
260 </div>
261 <div class="ui_element">
262 <button type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button" data-action="move-up" aria-label="<?php echo esc_attr__( 'Move up', 'booking' ); ?>">
263 <i class="menu_icon icon-1x wpbc_icn_arrow_upward"></i>
264 </button>
265 <button type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button" data-action="move-down" aria-label="<?php echo esc_attr__( 'Move down', 'booking' ); ?>">
266 <i class="menu_icon icon-1x wpbc_icn_arrow_downward"></i>
267 </button>
268 </div>
269 <div class="ui_element">
270 <?php /* ?>
271 <button data-action="duplicate" aria-label="<?php echo esc_attr__( 'Duplicate', 'booking' ); ?>" type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button">
272 <i class="menu_icon icon-1x wpbc_icn_content_copy"></i>
273 </button>
274 <?php */ ?>
275 <button data-action="delete" aria-label="<?php echo esc_attr__( 'Delete', 'booking' ); ?>" type="button" class="button button-secondary wpbc_ui_control wpbc_ui_button wpbc_ui_button_danger button-link-delete">
276 <span class="in-button-text"><?php echo esc_html__( 'Delete', 'booking' ); ?></span>&nbsp;&nbsp;<i class="menu_icon icon-1x wpbc_icn_delete_outline"></i>
277 </button>
278 </div>
279 </div><!-- .ui_group -->
280 </div><!-- .ui_container -->
281 </div><!-- .actions -->
282
283 <?php if ( ! function_exists( 'wpbc_is_mu_user_can_be_here' ) || wpbc_is_mu_user_can_be_here( 'only_super_admin' ) ) { ?>
284 <div class="wpbc_ui__collapsible_group" style="width: 99%;">
285 <div class="inspector__row row__bordered" style="background:#f8f8f8;border:0;justify-content: space-between;">
286 <label class="inspector__label"><?php echo esc_html__( 'Show as time picker', 'booking' ); ?></label>
287 <div class="inspector__control" style="flex: 0 1 auto;">
288 <input type="checkbox" class="inspector__checkbox js-toggle-timeslot-picker">
289 <p class="wpbc_bfb__help" style="margin-top:6px;">
290 <?php echo esc_html__( 'Toggle between selectbox and clickable time slots.', 'booking' ); ?>
291 </p>
292 </div>
293 <?php
294 $opt_name = 'booking_timeslot_picker';
295 $nonce_action = 'wpbc_nonce_' . $opt_name;
296 ?>
297 <a href="javascript:void(0);"
298 class="button button-secondary"
299 onclick="wpbc_save_option_from_element(this);"
300 data-wpbc-u-save-name="<?php echo esc_attr( $opt_name ); ?>"
301 data-wpbc-u-save-nonce="<?php echo esc_attr( wp_create_nonce( $nonce_action ) ); ?>"
302 data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
303 data-wpbc-u-save-value-from=".wpbc_bfb__inspector_timepicker .js-toggle-timeslot-picker"
304 data-wpbc-u-autosave-on-form-save="1"
305 data-wpbc-u-busy-text="<?php esc_attr_e( 'Saving', 'booking' ); ?>...">
306 <?php esc_html_e( 'Save Toggle', 'booking' ); ?>
307 </a>
308
309 </div>
310 </div>
311 <?php } ?>
312
313 </div><!-- .header_container -->
314 </div><!-- .wpbc_bfb__inspector__head -->
315
316 <div class="wpbc_bfb__inspector__body">
317
318 <section class="wpbc_bfb__inspector__group wpbc_ui__collapsible_group" data-group="basic">
319 <button type="button" class="group__header">
320 <h3><?php echo esc_html__( 'Basic', 'booking' ); ?></h3>
321 <i class="wpbc_ui_el__vert_menu_root_section_icon menu_icon icon-1x wpbc-bi-chevron-right"></i>
322 </button>
323 <div class="group__fields">
324 <div class="inspector__row">
325 <label class="inspector__label"><?php echo esc_html__( 'Label', 'booking' ); ?></label>
326 <div class="inspector__control">
327 <input type="text" class="inspector__input" data-inspector-key="label" value="{{ data.label || '<?php echo esc_js( __( 'Time', 'booking' ) ); ?>' }}">
328 </div>
329 </div>
330
331 <div class="inspector__row">
332 <label class="inspector__label"><?php echo esc_html__( 'Name', 'booking' ); ?></label>
333 <div class="inspector__control">
334 <?php
335 // Visible (disabled) field so users see it's fixed.
336 ?>
337 <input type="text"
338 class="inspector__input"
339 value="{{ (data.name && data.name !== '' ? data.name : 'rangetime') }}"
340 disabled="disabled"
341 aria-disabled="true">
342
343 <?php
344 // Hidden proxy that the Builder actually saves.
345 // Keep data-inspector-key on a non-disabled control.
346 ?>
347 <input type="hidden"
348 class="inspector__input js-locked-name"
349 data-inspector-key="name"
350 data-locked="1"
351 value="{{ (data.name && data.name !== '' ? data.name : 'rangetime') }}">
352
353 <p class="wpbc_bfb__help" style="margin-top:6px;">
354 <?php echo esc_html__( 'This field name is fixed for compatibility.', 'booking' ); ?>
355 </p>
356 </div>
357 </div>
358
359 <?php /* ?>
360 <div class="inspector__row">
361 <label class="inspector__label"><?php echo esc_html__( 'Required', 'booking' ); ?></label>
362 <div class="inspector__control">
363 <input type="checkbox" class="inspector__checkbox" data-inspector-key="required" <# if ( true === data.required || 'true' === data.required || 1 === data.required || '1' === data.required ) { #> checked <# } #> >
364 </div>
365 </div>
366 <?php */ ?>
367
368 <div class="inspector__row">
369 <div class="inspector__control ">
370 <span class="wpbc_ui__toggle">
371 <!-- Visible indicator: checked + disabled (tell normalizer to skip) -->
372 <# var input_id = window.WPBC_BFB_Core.UI.WPBC_BFB_Toggle_Normalizer.generate_unique_id( 'wpbc_ins_auto_' + 'toggle_required' + '_' ); #>
373 <input type="checkbox" id="{{input_id}}" class="inspector__checkbox js-required-visible" checked disabled aria-disabled="true" data-wpbc-ui-no-toggle="1">
374 <label class="wpbc_ui__toggle_icon" for="{{input_id}}"></label>
375 <label class="wpbc_ui__toggle_label" for="{{input_id}}"><?php echo esc_html__( 'Required', 'booking' ); ?></label>
376 </span>
377 <!-- PROXY for data binding (already skipped via flags) -->
378 <input type="checkbox" class="inspector__checkbox js-required-proxy" data-inspector-key="required" data-locked="1" checked data-wpbc-ui-no-toggle="1"
379 style="position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;">
380 <p class="wpbc_bfb__help" style="margin-inline-start:1em;display: inline-block;"><?php echo esc_html__( 'This field is always required.', 'booking' ); ?></p>
381 </div>
382 </div>
383
384 <div class="inspector__row">
385 <label class="inspector__label"><?php echo esc_html__( 'Help text', 'booking' ); ?></label>
386 <div class="inspector__control">
387 <textarea class="inspector__textarea" rows="3" data-inspector-key="help">{{ data.help || '' }}</textarea>
388 </div>
389 </div>
390 </div>
391 </section>
392
393 <section class="wpbc_bfb__inspector__group wpbc_ui__collapsible_group is-open" data-group="options">
394 <button type="button" class="group__header">
395 <h3><?php echo esc_html__( 'Time slots', 'booking' ); ?></h3>
396 <i class="wpbc_ui_el__vert_menu_root_section_icon menu_icon icon-1x wpbc-bi-chevron-right"></i>
397 </button>
398
399 <div class="group__fields inspector__group__fields__times">
400
401 <?php /* ===== Generator ===== */ ?>
402 <div class="inspector__row">
403 <div class="inspector__control inspector__control__generator_timeslots">
404
405 <# var __fmt_name = 'rt_label_fmt_' + ( data.html_id ? data.html_id : ( 'id_' + String( Math.random() ).slice(2) ) ); #>
406 <h2><?php echo esc_html__( 'Generate time slots', 'booking' ); ?></h2>
407 <div class="wpbc_bfb__rt_gen_format wpbc_inline_inputs" role="radiogroup" aria-label="<?php echo esc_attr__( 'Time format', 'booking' ); ?>">
408 <label class="inspector__label inspector__w_30"><?php echo esc_html__( 'Time format', 'booking' ); ?>:</label>
409 <div class="wpbc_inline_inputs inspector__w_70">
410 <?php /*
411 * PROXY input (single source-of-truth) so the core inspector serializer sees exactly one element
412 * with this key. Radios below are UI only and update this hidden value.
413 */ ?>
414 <input type="hidden"
415 class="inspector__input js-rt-label-fmt-value"
416 data-inspector-key="gen_label_fmt"
417 value="{{ data.gen_label_fmt || 'ampm' }}">
418
419 <# var __fmt_name = 'rt_label_fmt_' + ( data.html_id ? data.html_id : ( 'id_' + String( Math.random() ).slice(2) ) ); #>
420
421 <label>
422 <input type="radio"
423 name="{{ __fmt_name }}"
424 class="js-rt-label-fmt"
425 value="ampm"
426 <# if ( (data.gen_label_fmt||'ampm') === 'ampm' ) { #> checked <# } #> >
427 <?php echo esc_html__( 'AM/PM', 'booking' ); ?>
428 </label>
429 &nbsp;&nbsp;
430 <label>
431 <input type="radio"
432 name="{{ __fmt_name }}"
433 class="js-rt-label-fmt"
434 value="24h"
435 <# if ( data.gen_label_fmt === '24h' ) { #> checked <# } #> >
436 <?php echo esc_html__( '24H', 'booking' ); ?>
437 </label>
438 </div>
439 </div>
440
441
442 <div class="wpbc_bfb__rt_gen_times" style="margin-top:8px;">
443
444 <!-- 24H group (masked text inputs) -->
445 <div class="js-rt-24h wpbc_inline_inputs" <# if ( (data.gen_label_fmt||'ampm') === 'ampm' ) { #> style="display:none" hidden aria-hidden="true" <# } #>>
446 <label class="inspector__label inspector__w_30"><?php echo esc_html__( 'From / To', 'booking' ); ?>:</label>
447 <div class="wpbc_inline_inputs inspector__w_70">
448 <div class="inspector__control inspector__w_45">
449 <input type="text" class="inspector__input inspector__w_25 js-rt-mask js-gen-start-24h" data-mask-kind="24h" placeholder="HH:MM" data-inspector-key="gen_start_24h" value="{{ data.gen_start_24h || '09:00' }}">
450 </div>
451 <div class="inspector__control inspector__w_10" style="text-align: center;font-size: 18px;line-height: 2;font-weight: 700;">&ndash;</div>
452 <div class="inspector__control inspector__w_45">
453 <input type="text" class="inspector__input inspector__w_25 js-rt-mask js-gen-end-24h" data-mask-kind="24h" placeholder="HH:MM" data-inspector-key="gen_end_24h" value="{{ data.gen_end_24h || '18:00' }}">
454 </div>
455 </div>
456 </div>
457
458 <!-- AM/PM group (native time inputs) -->
459 <div class="js-rt-ampm wpbc_inline_inputs" <# if ( (data.gen_label_fmt||'ampm') !== 'ampm' ) { #> style="display:none" hidden aria-hidden="true" <# } #>>
460 <label class="inspector__label inspector__w_30"><?php echo esc_html__( 'From / To', 'booking' ); ?>:</label>
461 <div class="wpbc_inline_inputs inspector__w_70">
462 <div class="inspector__control inspector__w_45">
463 <input type="time" class="inspector__input inspector__w_25 js-gen-start-ampm-time" step="300" data-inspector-key="gen_start_ampm_t" value="{{ data.gen_start_ampm_t || '09:00' }}">
464 </div>
465 <div class="inspector__control inspector__w_10" style="text-align: center;font-size: 18px;line-height: 2;font-weight: 700;">&ndash;</div>
466 <div class="inspector__control inspector__w_45">
467 <input type="time" class="inspector__input inspector__w_25 js-gen-end-ampm-time" step="300" data-inspector-key="gen_end_ampm_t" value="{{ data.gen_end_ampm_t || '18:00' }}">
468 </div>
469 </div>
470 </div>
471 </div>
472
473 <div class="wpbc_bfb__rt_gen_step wpbc_inline_inputs">
474 <label class="inspector__label inspector__w_30"><?php echo esc_html__( 'Duration', 'booking' ); ?></label>
475 <div class="wpbc_len_group wpbc_inline_inputs inspector__w_70" data-len-group="rt-step-hours">
476 <div class="inspector__control inspector__w_10"><?php echo esc_html__( 'hours', 'booking' ); ?>:</div>
477 <input data-len-range type="range" class="inspector__input js-gen-step-h-range" min="0" max="12" step="1" value="{{ data.gen_step_h || 0 }}">
478 <input data-len-value type="number" class="inspector__input inspector__w_30 js-gen-step-h" data-inspector-key="gen_step_h" min="0" max="12" step="1" value="{{ data.gen_step_h || 0 }}">
479 </div>
480 </div>
481
482 <div class="wpbc_bfb__rt_gen_step wpbc_inline_inputs">
483 <label class="inspector__label inspector__w_30"></label>
484 <div class="wpbc_len_group wpbc_inline_inputs inspector__w_70" data-len-group="rt-step-minutes">
485 <div class="inspector__control inspector__w_10"><?php echo esc_html__( 'minutes', 'booking' ); ?>:</div>
486 <input data-len-range type="range" class="inspector__input js-gen-step-m-range" min="0" max="59" step="5" value="{{ data.gen_step_m || 30 }}">
487 <input data-len-value type="number" class="inspector__input inspector__w_30 js-gen-step-m" data-inspector-key="gen_step_m" min="0" max="59" step="5" value="{{ data.gen_step_m || 30 }}">
488 </div>
489 </div>
490
491 <div class="wpbc_bfb__options_toolbar wpbc_inline_inputs">
492 <div class="inspector__control inspector__w_100" style="text-align: center;">
493 <button type="button" class="button button-primary js-rt-generate"><?php echo esc_html__( 'Generate time slots', 'booking' ); ?> <i class="menu_icon icon-1x wpbc_icn_arrow_downward" aria-hidden="true"></i></button>
494 </div>
495 </div>
496
497 </div>
498 </div>
499
500 <?php /* ===== Options editor ===== */ ?>
501 <div class="inspector__row wpbc_bfb__options_editor">
502 <div class="wpbc_bfb__options_list__header">
503 <div class="wpbc_bfb__header_col__drag-handle"></div>
504 <div class="wpbc_bfb__header_col__label"><?php echo esc_html__( 'Label', 'booking' ) . ' (' . esc_html__( 'any text', 'booking' ) . ')'; ?></div>
505 <div class="wpbc_bfb__header_col__value" style="flex: 150px;"><?php echo esc_html__( 'Time slot', 'booking' ); ?></div>
506 <div class="wpbc_bfb__header_col__action"></div>
507 </div>
508 <div class="wpbc_bfb__options_list">
509 <#
510 var _opts2 = Array.isArray( data.options ) ? data.options
511 : ( function(o){ var a=[],k; for ( k in (o || {}) ) { if ( Object.prototype.hasOwnProperty.call( o, k ) ) { a.push( o[ k ] ); } } return a; } )( data.options );
512 #>
513
514 <# _opts2.forEach( function( opt, idx ){
515 var _val = String( opt && opt.value || '' );
516 var _parts = _val.split( /\s*-\s*/ );
517 var __start = _parts[0] || '';
518 var __end = _parts[1] || '';
519 var __uid = 'wpbc_ins_rt_' + Math.random().toString(36).slice(2,10);
520 var __sel = !!( opt && ( true === opt.selected || 'true' === opt.selected || 1 === opt.selected || '1' === opt.selected ) );
521 #>
522 <div class="wpbc_bfb__options_row" data-index="{{ idx }}">
523 <span class="wpbc_bfb__drag-handle" title="<?php echo esc_attr__( 'Drag to reorder', 'booking' ); ?>"><span class="wpbc_icn_drag_indicator"></span></span>
524
525 <input type="text" class="wpbc_bfb__opt-label" placeholder="<?php echo esc_attr__( 'Label (e.g. 10:00 AM - 10:30 AM)', 'booking' ); ?>" value="{{ opt && opt.label || '' }}">
526
527 <# if ( (data.gen_label_fmt||'ampm') === '24h' ) { #>
528 <input type="text" class="wpbc_bfb__opt-start js-rt-mask" data-mask-kind="24h" placeholder="HH:MM" value="{{ __start }}">
529 <span class="wpbc_bfb__opt-sep" aria-hidden="true">-</span>
530 <input type="text" class="wpbc_bfb__opt-end js-rt-mask" data-mask-kind="24h" placeholder="HH:MM" value="{{ __end }}">
531 <# } else { #>
532 <input type="time" class="wpbc_bfb__opt-start js-rt-start-time" step="300" value="{{ __start }}">
533 <span class="wpbc_bfb__opt-sep" aria-hidden="true">-</span>
534 <input type="time" class="wpbc_bfb__opt-end js-rt-end-time" step="300" value="{{ __end }}">
535 <# } #>
536
537 <input type="text" class="wpbc_bfb__opt-value" value="{{ _val }}" hidden>
538
539 <div class="wpbc_bfb__opt-selected">
540 <div class="inspector__control wpbc_ui__toggle">
541 <input type="checkbox" class="wpbc_bfb__opt-selected-chk inspector__input" id="{{ __uid }}" role="switch" aria-checked="{{ __sel ? 'true' : 'false' }}" <# if ( __sel ) { #> checked <# } #> >
542 <label class="wpbc_ui__toggle_icon_radio" for="{{ __uid }}"></label>
543 <label class="wpbc_ui__toggle_label" for="{{ __uid ?>"><?php echo esc_js( __( 'Default', 'booking' ) ); ?></label>
544 </div>
545 </div>
546
547 <div class="wpbc_ui_el wpbc_ui_el_container wpbc_ui_el__dropdown">
548 <a href="javascript:void(0)" data-toggle="wpbc_dropdown" aria-expanded="false" class="ul_dropdown_menu_toggle">
549 <i class="menu_icon icon-1x wpbc_icn_more_vert"></i>
550 </a>
551 <ul class="ul_dropdown_menu" role="menu" style="right:0px; left:auto;">
552 <li><a class="ul_dropdown_menu_li_action rt_dropdown_action" data-rt-action="add_after" href="javascript:void(0)"><?php echo esc_html__( 'Add New', 'booking' ); ?><i class="menu_icon icon-1x wpbc_icn_add_circle"></i></a></li>
553 <li><a class="ul_dropdown_menu_li_action rt_dropdown_action" data-rt-action="duplicate" href="javascript:void(0)"><?php echo esc_html__( 'Duplicate', 'booking' ); ?><i class="menu_icon icon-1x wpbc_icn_content_copy"></i></a></li>
554 <li class="divider"></li>
555 <li><a class="ul_dropdown_menu_li_action rt_dropdown_action" data-rt-action="remove" href="javascript:void(0)"><?php echo esc_html__( 'Remove', 'booking' ); ?><i class="menu_icon icon-1x wpbc_icn_delete_outline"></i></a></li>
556 </ul>
557 </div>
558 </div>
559 <# }); #>
560 </div>
561
562 <div class="wpbc_bfb__options_toolbar ">
563 <small class="desc"><?php echo esc_html__( 'Drag by handle to reorder. For single-select, only one “Default” can be checked.', 'booking' ); ?></small>
564 <div class="wpbc_bfb__options_toolbar wpbc_inline_inputs">
565 <div class="inspector__control inspector__w_15">
566 <button type="button" class="button js-rt-clear"><?php
567 echo esc_html__( 'Clear all', 'booking' ); ?></button>
568 </div>
569 <div class="inspector__control inspector__w_85">
570 <button type="button" class="button button-secondary js-rt-add-option">
571 <i class="wpbc_ui_el__vert_nav_icon tooltip_right_offset menu_icon icon-1x wpbc_icn_add_circle" aria-hidden="true"></i>
572 <?php echo esc_html__( 'Add time slot', 'booking' ); ?>
573 </button>
574 </div>
575 </div>
576 </div>
577
578 <#
579 var __json = JSON.stringify(_opts2 || []);
580 __json = __json.replace(/<\/textarea/gi, '<\\/textarea');
581 #>
582 <textarea class="wpbc_bfb__options_state inspector__input" data-inspector-key="options" hidden>{{ __json }}</textarea>
583 </div>
584
585
586 <div class="inspector__row js-placeholder-row">
587 <label class="inspector__label"><?php echo esc_html__( 'Placeholder (single only)', 'booking' ); ?></label>
588 <div class="inspector__control">
589 <input type="text" class="inspector__input js-placeholder" data-inspector-key="placeholder" value="{{ data.placeholder || '<?php echo '--- ' . esc_js( __( 'Select time', 'booking' ) ) . ' ---'; ?>' }}">
590 <p class="wpbc_bfb__help js-placeholder-note" style="margin-top:6px; display:none;"><?php echo esc_html__( 'Placeholder is used only for single-select when no default is set.', 'booking' ); ?></p>
591 </div>
592 </div>
593 <?php /* ?>
594 <div class="inspector__row">
595 <label class="inspector__label"><?php echo esc_html__( 'Allow multiple selection', 'booking' ); ?></label>
596 <div class="inspector__control">
597 <input type="checkbox" class="inspector__checkbox js-opt-multiple" data-inspector-key="multiple"
598 <# if ( true === data.multiple || 'true' === data.multiple || 1 === data.multiple || '1' === data.multiple ) { #> checked <# } #> >
599 </div>
600 </div>
601
602 <div class="inspector__row">
603 <label class="inspector__label"><?php echo esc_html__( 'Size (rows, for multiple)', 'booking' ); ?></label>
604 <div class="inspector__control">
605 <div class="wpbc_len_group wpbc_inline_inputs" data-len-group="select-size-rows">
606 <input data-len-range type="range" class="inspector__input" min="2" max="20" step="1" value="{{ data.size || '' }}">
607 <input data-len-value type="number" class="inspector__input inspector__w_30" data-inspector-key="size" min="2" max="20" value="{{ data.size || '' }}">
608 </div>
609 </div>
610 </div>
611 <?php */ ?>
612
613
614
615 </div>
616 </section>
617
618 <section class="wpbc_bfb__inspector__group wpbc_ui__collapsible_group" data-group="appearance">
619 <button type="button" class="group__header">
620 <h3><?php echo esc_html__( 'Appearance', 'booking' ); ?></h3>
621 <i class="wpbc_ui_el__vert_menu_root_section_icon menu_icon icon-1x wpbc-bi-chevron-right"></i>
622 </button>
623 <div class="group__fields">
624
625 <div class="inspector__row">
626 <label class="inspector__label"><?php echo esc_html__( 'CSS class', 'booking' ); ?></label>
627 <div class="inspector__control">
628 <input type="text" class="inspector__input" data-inspector-key="cssclass" value="{{ data.cssclass || '' }}">
629 </div>
630 </div>
631
632 <div class="inspector__row">
633 <label class="inspector__label"><?php echo esc_html__( 'HTML ID', 'booking' ); ?></label>
634 <div class="inspector__control">
635 <input type="text" class="inspector__input" data-inspector-key="html_id" value="{{ data.html_id || '' }}">
636 </div>
637 </div>
638
639 <div class="inspector__row">
640 <label class="inspector__label"><?php echo esc_html__( 'Min width', 'booking' ); ?></label>
641 <div class="inspector__control">
642 <input type="text" class="inspector__input" data-inspector-key="min_width" placeholder="240px" value="{{ data.min_width || '240px' }}">
643 </div>
644 </div>
645 </div>
646 </section>
647
648 <?php /* ?>
649 <section class="wpbc_bfb__inspector__group wpbc_ui__collapsible_group" data-group="advanced">
650 <button type="button" class="group__header">
651 <h3><?php echo esc_html__( 'Advanced', 'booking' ); ?></h3>
652 <i class="wpbc_ui_el__vert_menu_root_section_icon menu_icon icon-1x wpbc-bi-chevron-right"></i>
653 </button>
654 <div class="group__fields">
655 <div class="inspector__row">
656 <label class="inspector__label"><?php echo esc_html__( 'Default (value or CSV for multiple)', 'booking' ); ?></label>
657 <div class="inspector__control">
658 <input type="text" class="inspector__input js-default-value" data-inspector-key="default_value" value="{{ data.default_value || '' }}">
659 <p class="wpbc_bfb__help js-default-value-note" style="margin-top:6px; display:none;"><?php echo esc_html__( 'Clear row defaults to use the text field.', 'booking' ); ?></p>
660 </div>
661 </div>
662 </div>
663 </section>
664 <?php */ ?>
665
666 </div><!-- .wpbc_bfb__inspector__body -->
667 </div><!-- .wpbc_bfb__inspector_rangetime wpbc_bfb__inspector_timepicker-->
668 </script>
669
670 <?php
671 }
672