PluginProbe
Booking Calendar / 11.0
Booking Calendar v11.0
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-duration / _src / field-durationtime-wptpl.js

field-durationtime-wptpl.js in Booking Calendar 11.0, at includes/page-form-builder/field-packs/time-duration/_src/field-durationtime-wptpl.js

312 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // ---------------------------------------------------------------------------------------------------------------------
2 // == File /includes/page-form-builder/field-packs/time-durationtime/_out/field-durationtime-wptpl.js
3 // == Pack Duration Time (WP-template–driven) — reuses Start Time inspector logic via shared selectors
4 // == Depends on Core: WPBC_BFB_Field_Base, Field_Renderer_Registry, Core.Time utils, StartTime pack (events)
5 // == Version 1.0.3 (04.11.2025 13:22)
6 // ---------------------------------------------------------------------------------------------------------------------
7 (function (w, d) {
8 'use strict';
9
10 var Core = w.WPBC_BFB_Core || {};
11 var Registry = Core.WPBC_BFB_Field_Renderer_Registry;
12 var Base = Core.WPBC_BFB_Field_Base || null;
13 var Time = (Core && Core.Time) ? Core.Time : null;
14
15 if ( !Registry || typeof Registry.register !== 'function' || !Base || !Time ) {
16 if ( w._wpbc && w._wpbc.dev && w._wpbc.dev.error ) {
17 w._wpbc.dev.error( 'wpbc_bfb_field_durationtime', 'Missing Core registry/base/time-utils' );
18 }
19 return;
20 }
21
22 // ---------------------------------------------------------------------
23 // Helpers (label humanizer + row relabel)
24 // ---------------------------------------------------------------------
25 function humanize_minutes_label( totalMins ){
26 if ( isNaN(totalMins) || totalMins < 0 ) { return ''; }
27 var h = Math.floor( totalMins / 60 );
28 var m = totalMins % 60;
29
30 // i18n fallbacks
31 var i18n_minutes = w.wpbc_i18n_minutes || 'minutes';
32 var i18n_min = w.wpbc_i18n_min || 'min';
33 var i18n_h = w.wpbc_i18n_h || 'h';
34
35 if ( h === 0 ) {
36 // "15 minutes"
37 return String( m ) + ' ' + i18n_minutes;
38 }
39 // "1h" or "1h 15m"
40 return ( h + i18n_h ) + ( m > 0 ? ( ' ' + m + (w.wpbc_i18n_m || 'm') ) : '' );
41 }
42
43 function relabel_rows_in_duration_panel( panel ){
44 if ( ! panel ) { return; }
45 // Only touch our pack
46 var dtype = panel.getAttribute('data-type') || '';
47 if ( dtype !== 'durationtime' ) { return; }
48
49 var list = panel.querySelector('.wpbc_bfb__options_list');
50 if ( ! list ) { return; }
51
52 list.querySelectorAll('.wpbc_bfb__options_row').forEach(function(row){
53 var valEl = row.querySelector('.wpbc_bfb__opt-value'); // authoritative 24h value holder
54 var timeEl = row.querySelector('.wpbc_bfb__opt-time'); // visible editor
55 var raw = (valEl && valEl.value) || (timeEl && timeEl.value) || '';
56 var mins = Time.parse_hhmm_24h( String(raw) );
57 if ( isNaN(mins) ) { return; }
58
59 var labelEl = row.querySelector('.wpbc_bfb__opt-label');
60 if ( ! labelEl ) { return; }
61
62 // Set default humanized label (user can edit later; we do this only on generation)
63 labelEl.value = humanize_minutes_label( mins );
64 });
65
66 // Re-sync the hidden JSON state after relabel
67 try {
68 var ST = w.WPBC_BFB_Field_StartTime;
69 if ( ST && typeof ST.sync_state_from_rows === 'function' ) {
70 ST.sync_state_from_rows( panel );
71 }
72 } catch(e){}
73 }
74
75 // ---------------------------------------------------------------------
76 // Event wiring (react to StartTime generator completion)
77 // ---------------------------------------------------------------------
78 (function bind_generation_listeners_once(){
79 if ( w.__wpbc_dt_bound ) { return; }
80 w.__wpbc_dt_bound = true;
81
82 // DOM CustomEvent path
83 d.addEventListener('wpbc_bfb_time_options_generated', function(ev){
84 try {
85 var panel = ev && ev.target;
86 var detail= ev && ev.detail || {};
87 // Only for Duration Time panels
88 var dtype = (detail && detail.type) || (panel && panel.getAttribute('data-type')) || '';
89 if ( dtype !== 'durationtime' ) { return; }
90 relabel_rows_in_duration_panel( panel );
91 } catch(e){}
92 }, true);
93
94 // Core bus path (if available)
95 try {
96 var EVNAME = (Core && Core.WPBC_BFB_Events && Core.WPBC_BFB_Events.TIME_OPTIONS_GENERATED) || 'wpbc_bfb:time_options_generated';
97 if ( Core && Core.bus && typeof Core.bus.on === 'function' ) {
98 Core.bus.on( EVNAME, function(payload){
99 try {
100 if ( !payload || payload.type !== 'durationtime' ) { return; }
101 relabel_rows_in_duration_panel( payload.panel );
102 } catch(e){}
103 });
104 }
105 } catch(e){}
106 })();
107
108 /**
109 * WPBC_BFB: Duration Time field renderer (template-driven).
110 * Inspector is structurally identical to Start Time, so we intentionally reuse:
111 * - root class: .wpbc_bfb__inspector_starttime (Start Time JS binds here)
112 * - option rows markup / state syncing (delegated to Start Time JS)
113 */
114 const wpbc_bfb_field_durationtime = class extends Base {
115
116 static template_id = 'wpbc-bfb-field-durationtime';
117 static kind = 'durationtime';
118
119 static get_defaults(){
120 return {
121 kind : 'field',
122 type : 'durationtime',
123 label : 'Duration time',
124 name : 'durationtime',
125 html_id : '',
126 required : true,
127 multiple : false,
128 size : null,
129 cssclass : '',
130 help : '',
131 default_value : '',
132 placeholder : '--- Select duration time ---',
133 value_differs : true,
134 min_width : '180px',
135
136 // 24h labels by default make sense for durations (values are 24h, labels will be humanized on generation).
137 options : [
138 { label: '00:15', value: '00:15', selected: false },
139 { label: '00:30', value: '00:30', selected: false },
140 { label: '00:45', value: '00:45', selected: false },
141 { label: '01:00', value: '01:00', selected: false },
142 { label: '01:30', value: '01:30', selected: false },
143 { label: '02:00', value: '02:00', selected: false }
144 ],
145
146 // Generator defaults (min/max duration).
147 // NOTE: We keep '24h' internally but hide the UI in the template (no AM/PM vs 24h for durations).
148 gen_label_fmt : '24h',
149 gen_start_24h : '00:15',
150 gen_end_24h : '06:00',
151 gen_start_ampm_t: '00:15',
152 gen_end_ampm_t : '06:00',
153 gen_step_h : 0,
154 gen_step_m : 15
155 };
156 }
157
158 /**
159 * After the field is dropped from the palette.
160 * Locks "name" to 'durationtime' and ensures required=true for consistency.
161 *
162 * @param {Object} data
163 * @param {HTMLElement} el
164 * @param {Object} ctx
165 */
166 static on_field_drop( data, el, ctx ){
167 if ( super.on_field_drop ) { super.on_field_drop( data, el, ctx ); }
168 try {
169 if ( data && typeof data === 'object' ) {
170 data.name = 'durationtime';
171 data.required = true;
172 if ( ! data.placeholder ) {
173 data.placeholder = '--- ' + ( (w.wpbc_i18n_select_durationtime) || 'Select duration time' ) + ' ---';
174 }
175 // Keep 24h format internally; the UI radios are hidden in the template.
176 data.gen_label_fmt = data.gen_label_fmt || '24h';
177 }
178 if ( el && el.dataset ) {
179 el.dataset.name = 'durationtime';
180 el.dataset.autoname = '0';
181 el.dataset.fresh = '0';
182 el.dataset.name_user_touched = '1';
183 el.setAttribute( 'data-required', 'true' );
184 }
185 var sel = el && el.querySelector( 'select.wpbc_bfb__preview-timepicker' );
186 if ( sel ) { sel.setAttribute( 'name', 'durationtime' ); }
187 } catch(e){}
188 }
189 };
190
191 try { Registry.register( 'durationtime', wpbc_bfb_field_durationtime ); }
192 catch ( e ) { if ( w._wpbc && w._wpbc.dev && w._wpbc.dev.error ) { w._wpbc.dev.error( 'wpbc_bfb_field_durationtime.register', e ); } }
193
194 // No extra bindings; Start Time pack listeners handle the inspector via shared classes.
195 // This file only post-processes generated options via events.
196 w.WPBC_BFB_Field_DurationTime = wpbc_bfb_field_durationtime;
197
198 // -----------------------------------------------------------------------------------------------------------------
199 // Export for "Booking Form" (Advanced Form shortcode)
200 // -----------------------------------------------------------------------------------------------------------------
201 /**
202 * Booking Form exporter callback for "durationtime".
203 *
204 * Mirrors the legacy behavior:
205 * WPBC_BFB_Exporter.emit_time_select( name, field, req_mark, id_opt, cls_opts, emit_label_then );
206 *
207 * So the final shortcode body and label handling are identical to the old
208 * switch/case path in builder-exporter.js, just moved into this pack.
209 */
210 function register_durationtime_booking_form_exporter() {
211
212 var Exp = w.WPBC_BFB_Exporter;
213 if ( ! Exp || typeof Exp.register !== 'function' ) { return; }
214 if ( typeof Exp.has_exporter === 'function' && Exp.has_exporter( 'durationtime' ) ) { return; }
215
216 var S = Core.WPBC_BFB_Sanitize || {};
217 var esc_html = S.escape_html || function( v ){ return String( v ); }; // kept for parity with Start/End Time
218
219 /**
220 * @type {WPBC_BFB_ExporterCallback}
221 */
222 var exporter_callback = function( field, emit, extras ) {
223 extras = extras || {};
224
225 var cfg = extras.cfg || {};
226 var ctx = extras.ctx;
227
228 // Shared label wrapper: same pattern as Start/End Time.
229 var emit_label_then = function( body ) {
230 // Preferred path: centralized helper in builder-exporter.js
231 if ( Exp && typeof Exp.emit_label_then === 'function' ) {
232 Exp.emit_label_then( field, emit, body, cfg );
233 return;
234 }
235 // No fallback (aligned with Start/End Time packs).
236 };
237
238 // Required marker.
239 var is_req = Exp.is_required( field );
240 var req_mark = is_req ? '*' : '';
241
242 // Name / id / classes from shared helpers so they stay in sync.
243 var name = Exp.compute_name( 'durationtime', field );
244 var id_opt = Exp.id_option( field, ctx );
245 var cls_opts = Exp.class_options( field );
246
247 // Dedicated time helper to keep exact legacy shortcode shape.
248 if ( typeof Exp.emit_time_select === 'function' ) {
249 Exp.emit_time_select( name, field, req_mark, id_opt, cls_opts, emit_label_then );
250 return;
251 }
252 };
253
254 Exp.register( 'durationtime', exporter_callback );
255 }
256
257 if ( w.WPBC_BFB_Exporter && typeof w.WPBC_BFB_Exporter.register === 'function' ) {
258 register_durationtime_booking_form_exporter();
259 } else if ( typeof document !== 'undefined' ) {
260 document.addEventListener( 'wpbc:bfb:exporter-ready', register_durationtime_booking_form_exporter, { once: true } );
261 }
262
263
264 // -----------------------------------------------------------------------------------------------------------------
265 // Export for "Booking Data" (Content of booking fields data)
266 // -----------------------------------------------------------------------------------------------------------------
267 /**
268 * Booking Data exporter callback for "durationtime".
269 *
270 * Default behavior:
271 * <b>Label</b>: <f>[durationtime]</f><br>
272 *
273 * The exported token name is kept fully in sync with the Booking Form exporter
274 * via Exp.compute_name('durationtime', field).
275 */
276 function register_durationtime_booking_data_exporter() {
277
278 var C = w.WPBC_BFB_ContentExporter;
279 if ( ! C || typeof C.register !== 'function' ) { return; }
280 if ( typeof C.has_exporter === 'function' && C.has_exporter( 'durationtime' ) ) { return; }
281
282 C.register( 'durationtime', function( field, emit, extras ) {
283 extras = extras || {};
284 var cfg = extras.cfg || {};
285
286 var Exp = w.WPBC_BFB_Exporter;
287 if ( ! Exp || typeof Exp.compute_name !== 'function' ) { return; }
288
289 // Base name, identical to Booking Form exporter.
290 var name = Exp.compute_name( 'durationtime', field );
291 if ( ! name ) { return; }
292
293 var raw_label = ( typeof field.label === 'string' ) ? field.label : '';
294 var label = raw_label.trim() || name;
295
296 // Build a combined token: [name] / [name_val]
297 // emit_line_bold_field will wrap it as: <f>[{token}]</f>
298 var token = name + '_val] / [' + name;
299
300 // Result: <b>Label</b>: <f>[durationtime_val] / [durationtime]</f><br>
301 C.emit_line_bold_field( emit, label, token, cfg );
302 } );
303 }
304
305 if ( w.WPBC_BFB_ContentExporter && typeof w.WPBC_BFB_ContentExporter.register === 'function' ) {
306 register_durationtime_booking_data_exporter();
307 } else if ( typeof document !== 'undefined' ) {
308 document.addEventListener( 'wpbc:bfb:content-exporter-ready', register_durationtime_booking_data_exporter, { once: true } );
309 }
310
311 })( window, document );
312