PluginProbe
Booking Calendar / 11.7
Booking Calendar v11.7
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 10.11 All 204 releases
booking / includes / page-form-builder / field-packs / textarea / _src / textarea.js

textarea.js in Booking Calendar 11.7, at includes/page-form-builder/field-packs/textarea/_src/textarea.js

277 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * WPBC BFB: Textarea Renderer (Schema-driven)
3 * =====================================================================================================================
4 * File: /includes/page-form-builder/field-packs/textarea/_out/textarea.js
5 * =====================================================================================================================
6 */
7 (function (w) {
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;
13
14 if ( ! registry || typeof registry.register !== 'function' || ! Base ) {
15 _wpbc?.dev?.error?.( 'WPBC_BFB_Field_Textarea', 'Core registry/base missing' );
16 return;
17 }
18
19 /**
20 * WPBC BFB: Field Renderer for "textarea" (Schema-driven, template-literal render)
21 *
22 * Contracts:
23 * - Registry: WPBC_BFB_Field_Renderer_Registry.register( 'textarea', Class )
24 * - Class API: static get_defaults(), static render(el, data, ctx), static on_field_drop(data, el, ctx?) [optional]
25 *
26 * Notes:
27 * - Keep defaults aligned with PHP schema->props->default.
28 * - Uses WPBC_BFB_Sanitize helpers from Core.
29 * - Uses Overlay.ensure(...) so field controls (handle, settings, etc.) appear.
30 */
31 class WPBC_BFB_Field_Textarea extends Base {
32
33 /**
34 * Return default props for "textarea" field.
35 * Must stay in sync with PHP schema defaults.
36 *
37 * @returns {Object}
38 */
39 static get_defaults() {
40 return {
41 type : 'textarea',
42 label : 'Textarea',
43 name : '',
44 html_id : '',
45 placeholder : '',
46 required : false,
47 minlength : null,
48 maxlength : null,
49 rows : 4,
50 cssclass : '',
51 help : '',
52 default_value: '',
53 min_width : '260px'
54 };
55 }
56
57 /**
58 * Render the preview markup into the field element.
59 *
60 * @param {HTMLElement} el Field root element inside the canvas.
61 * @param {Object} data Field props (already normalized by schema).
62 * @param {Object} ctx Context: { builder, sanit, ... }
63 */
64 static render(el, data, ctx) {
65 if ( ! el ) {
66 return;
67 }
68
69 // Normalize against defaults first.
70 const d = this.normalize_data( data );
71
72 // ----- Core sanitize helpers (static) -----
73 const eh = (v) => Core.WPBC_BFB_Sanitize.escape_html( v );
74 const sid = (v) => Core.WPBC_BFB_Sanitize.sanitize_html_id( v );
75 const sname = (v) => Core.WPBC_BFB_Sanitize.sanitize_html_name( v );
76 const sclass = (v) => Core.WPBC_BFB_Sanitize.sanitize_css_classlist( v );
77 const truthy = (v) => Core.WPBC_BFB_Sanitize.is_truthy( v );
78
79 // Sanitize public id/name for the control itself.
80 const html_id = d.html_id ? sid( String( d.html_id ) ) : '';
81 const name_val = sname( String( d.name || d.id || 'field' ) );
82 const css_next = sclass( String( d.cssclass || '' ) );
83
84 // Keep dataset in sync (do not mutate wrapper classes).
85 if ( 'cssclass' in d && el.dataset.cssclass !== css_next ) {
86 el.dataset.cssclass = css_next;
87 }
88 if ( 'html_id' in d && el.dataset.html_id !== html_id ) {
89 el.dataset.html_id = html_id;
90 }
91 // NEW: persist min_width for the Min-Width guard / layout controller.
92 if ( d.min_width ) {
93 el.dataset.min_width = String( d.min_width );
94 el.style.setProperty( '--wpbc-col-min', String( d.min_width ) );
95 }
96
97 // Flags / numeric constraints.
98 const is_required = truthy( d.required );
99 const has_minlength = (d.minlength != null && d.minlength !== '' && Number.isFinite( +d.minlength ));
100 const has_maxlength = (d.maxlength != null && d.maxlength !== '' && Number.isFinite( +d.maxlength ));
101 const rows_num = (d.rows != null && Number.isFinite( +d.rows ) && +d.rows > 0)
102 ? Math.max( 1, Math.min( 50, +d.rows ) )
103 : 4;
104
105 const minlength_num = has_minlength ? Number( d.minlength ) : null;
106 const maxlength_num = has_maxlength ? Number( d.maxlength ) : null;
107
108 // Attribute fragments.
109 const id_attr = html_id ? ` id="${eh( html_id )}"` : '';
110 const name_attr = ` name="${eh( name_val )}"`;
111 // Include the base preview class so the canvas styles apply.
112 const cls_attr = ` class="wpbc_bfb__preview-input wpbc_bfb__preview-textarea${css_next ? ' ' + eh( css_next ) : ''}"`;
113 const ph_attr = d.placeholder ? ` placeholder="${eh( d.placeholder )}"` : '';
114 const req_attr = is_required ? ' required aria-required="true"' : '';
115 const minlength_attr = has_minlength ? ` minlength="${minlength_num}"` : '';
116 const maxlength_attr = has_maxlength ? ` maxlength="${maxlength_num}"` : '';
117 const rows_attr = ` rows="${rows_num}"`;
118
119 const label_html = (d.label != null && d.label !== '')
120 ? `<label class="wpbc_bfb__field-label"${html_id ? ` for="${eh( html_id )}"` : ''}>${eh( d.label )}${is_required ? '<span aria-hidden="true">*</span>' : ''}</label>`
121 : '';
122
123 const help_html = d.help ? `<div class="wpbc_bfb__help">${eh( d.help )}</div>` : '';
124 const default_text = (d.default_value != null && d.default_value !== '') ? eh( String( d.default_value ) ) : '';
125
126 el.innerHTML = `
127 <span class="wpbc_bfb__noaction wpbc_bfb__no-drag-zone" inert="">
128 ${label_html}
129 <span class="wpbc_wrap_text wpdev-form-control-wrap">
130 <textarea${cls_attr}${ph_attr}${name_attr} tabindex="-1" aria-disabled="true"${id_attr}${rows_attr}${req_attr}${minlength_attr}${maxlength_attr}>${default_text}</textarea>
131 </span>
132 ${help_html}
133 </span>
134 `;
135
136 // Overlay (handles/toolbars).
137 Core.UI?.WPBC_BFB_Overlay?.ensure?.( ctx?.builder, el );
138 }
139
140 /**
141 * Optional hook executed after field is dropped from the palette.
142 *
143 * @param {Object} data Palette/field data.
144 * @param {HTMLElement} el Newly created field element.
145 * @param {Object} ctx Context { builder, sanit, context: 'drop' | 'load' | 'preview' }
146 * @returns {void}
147 */
148 static on_field_drop(data, el, ctx) {
149 super.on_field_drop?.( data, el, ctx );
150 }
151 }
152
153 try {
154 registry.register( 'textarea', WPBC_BFB_Field_Textarea );
155 } catch ( e ) {
156 _wpbc?.dev?.error?.( 'WPBC_BFB_Field_Textarea.register', e );
157 }
158
159
160 // -----------------------------------------------------------------------------------------------------------------
161 // Export for "Booking Form" (Advanced Form shortcode)
162 // -----------------------------------------------------------------------------------------------------------------
163 /**
164 * Booking Form exporter callback for "textarea".
165 *
166 * Produces shortcodes equivalent to the legacy exporter:
167 * [textarea* your-name 40x4 id:your-name class:your-class "Default text"]
168 *
169 * Labels and help text are handled in the same centralized way as other packs.
170 */
171 function register_textarea_booking_form_exporter() {
172
173 var Exp = w.WPBC_BFB_Exporter;
174 if ( ! Exp || typeof Exp.register !== 'function' ) { return; }
175 if ( typeof Exp.has_exporter === 'function' && Exp.has_exporter( 'textarea' ) ) { return; }
176
177 var S = Core.WPBC_BFB_Sanitize || {};
178
179 /**
180 * @type {WPBC_BFB_ExporterCallback}
181 */
182 Exp.register( 'textarea', function( field, emit, extras ) {
183 extras = extras || {};
184
185 var cfg = extras.cfg || {};
186 var ctx = extras.ctx;
187 var addLabels = cfg.addLabels !== false;
188
189 // Required marker (same semantics as text field).
190 var is_req = Exp.is_required( field );
191 var req_mark = is_req ? '*' : '';
192
193 // Shared helpers keep naming / id / classes consistent across packs.
194 var name = Exp.compute_name( 'textarea', field );
195 var id_opt = Exp.id_option( field, ctx );
196 var cls_opts = Exp.class_options( field );
197 var ph_attr = Exp.ph_attr( field && field.placeholder );
198 var def_text = Exp.default_text_suffix( field );
199
200 // Rows token: [textarea name x5] — rows come from schema/Inspector (`field.rows`).
201 // Clamp into [1,50] to mirror Inspector constraints.
202 var rows_token = '';
203 if ( field && field.rows != null && field.rows !== '' ) {
204 var r = Number( field.rows );
205 if ( ! Number.isFinite( r ) ) {
206 r = 4;
207 }
208 if ( r < 1 ) { r = 1; }
209 if ( r > 50 ) { r = 50; }
210 rows_token = ' x' + String( r );
211 }
212
213 // Final shortcode body (rows-only sizing; no columns), e.g.:
214 // [textarea* your-message x5 id:your-message class:... "Default text"]
215 var body = '[textarea' + req_mark + ' ' + name + rows_token + id_opt + cls_opts + ph_attr + def_text + ']';
216
217 // Label behavior mirrors legacy emit_label_then().
218 var raw_label = ( field && typeof field.label === 'string' ) ? field.label : '';
219 var label = raw_label.trim();
220
221 if ( label && addLabels ) {
222 emit( '<l>' + (S.escape_html ? S.escape_html( label ) : label) + req_mark + '</l>' );
223 emit( '<br>' + body );
224 } else {
225 emit( body );
226 }
227 // Help text is appended centrally by WPBC_BFB_Exporter.render_field_node().
228 } );
229 }
230
231 if ( w.WPBC_BFB_Exporter && typeof w.WPBC_BFB_Exporter.register === 'function' ) {
232 register_textarea_booking_form_exporter();
233 } else if ( typeof document !== 'undefined' ) {
234 document.addEventListener( 'wpbc:bfb:exporter-ready', register_textarea_booking_form_exporter, { once: true } );
235 }
236
237
238 // -----------------------------------------------------------------------------------------------------------------
239 // Export for "Booking Data" (Content of booking fields data)
240 // -----------------------------------------------------------------------------------------------------------------
241 /**
242 * Booking Data exporter ("Content of booking fields data") for "textarea".
243 *
244 * Default line format:
245 * <b>Label</b>: <f>[field_name]</f><br>
246 */
247 function register_textarea_booking_data_exporter() {
248
249 var C = w.WPBC_BFB_ContentExporter;
250 if ( ! C || typeof C.register !== 'function' ) { return; }
251 if ( typeof C.has_exporter === 'function' && C.has_exporter( 'textarea' ) ) { return; }
252
253 C.register( 'textarea', function( field, emit, extras ) {
254 extras = extras || {};
255 var cfg = extras.cfg || {};
256
257 var Exp = w.WPBC_BFB_Exporter;
258 if ( ! Exp || typeof Exp.compute_name !== 'function' ) { return; }
259
260 var name = Exp.compute_name( 'textarea', field );
261 if ( ! name ) { return; }
262
263 var label = ( field && typeof field.label === 'string' && field.label.trim() ) ? field.label.trim() : name;
264
265 // Shared helper keeps formatting consistent across all packs.
266 C.emit_line_bold_field( emit, label, name, cfg );
267 } );
268 }
269
270 if ( w.WPBC_BFB_ContentExporter && typeof w.WPBC_BFB_ContentExporter.register === 'function' ) {
271 register_textarea_booking_data_exporter();
272 } else if ( typeof document !== 'undefined' ) {
273 document.addEventListener( 'wpbc:bfb:content-exporter-ready', register_textarea_booking_data_exporter, { once: true } );
274 }
275
276 })( window );
277