| 1 |
/** |
| 2 |
* WPBC BFB: Field Renderer for "text" (WP-template–driven Reference, no fallback) |
| 3 |
* ========================================================================= |
| 4 |
* - Uses wp.template('wpbc-bfb-field-text') for preview |
| 5 |
* - If template is unavailable or fails, shows an inline error message |
| 6 |
* - Inspector UI is produced by wp.template('wpbc-bfb-inspector-text') |
| 7 |
* - Assumes wpbc-bfb_core provides WPBC_BFB_Sanitize |
| 8 |
* |
| 9 |
* Contracts: |
| 10 |
* - Registry: WPBC_BFB_Field_Renderer_Registry.register('text', Class) |
| 11 |
* - Class API: static get_defaults(), static render(el, data, ctx), static on_field_drop(data, el, ctx?) [optional] |
| 12 |
* |
| 13 |
* File: ../includes/page-form-builder/field-packs/text/_out/field-text-wptpl.js |
| 14 |
* |
| 15 |
* @since 11.0.0 |
| 16 |
* @modified 2025-09-06 14:08 |
| 17 |
* @version 1.0.1 |
| 18 |
*/ |
| 19 |
(function (w) { |
| 20 |
'use strict'; |
| 21 |
|
| 22 |
var Core = w.WPBC_BFB_Core || {}; |
| 23 |
var Registry = Core.WPBC_BFB_Field_Renderer_Registry; |
| 24 |
var Base = Core.WPBC_BFB_Field_Base; |
| 25 |
|
| 26 |
if ( ! Registry || typeof Registry.register !== 'function' || ! Base ) { |
| 27 |
_wpbc?.dev?.error?.( 'WPBC_BFB_Field_Text', 'Core registry/base missing' ); |
| 28 |
return; |
| 29 |
} |
| 30 |
|
| 31 |
class WPBC_BFB_Field_Text extends Base { |
| 32 |
|
| 33 |
/** Template id without the "tmpl-" prefix (Base will normalize/caches it). */ |
| 34 |
static template_id = 'wpbc-bfb-field-text'; |
| 35 |
|
| 36 |
static get_defaults() { |
| 37 |
return { |
| 38 |
type : 'text', |
| 39 |
label : 'Text', |
| 40 |
name : '', |
| 41 |
html_id : '', |
| 42 |
placeholder : '', |
| 43 |
required : false, |
| 44 |
minlength : null, |
| 45 |
maxlength : null, |
| 46 |
pattern : '', |
| 47 |
cssclass : '', |
| 48 |
help : '', |
| 49 |
default_value: '' |
| 50 |
}; |
| 51 |
} |
| 52 |
|
| 53 |
/** |
| 54 |
* Render via wp.template; if missing, print a tiny error message. |
| 55 |
* |
| 56 |
* @param {HTMLElement} el |
| 57 |
* @param {Object} data |
| 58 |
* @param {Object} ctx |
| 59 |
*/ |
| 60 |
static render(el, data, ctx) { |
| 61 |
|
| 62 |
if ( ! el ) { |
| 63 |
return; |
| 64 |
} |
| 65 |
|
| 66 |
// Normalize first (mirrors Base.render). |
| 67 |
const d = this.normalize_data( data ); |
| 68 |
|
| 69 |
// Sanitize helpers actually available in core. |
| 70 |
const S = Core.WPBC_BFB_Sanitize; |
| 71 |
const html_id = d.html_id ? S.sanitize_html_id( String( d.html_id ) ) : ''; |
| 72 |
const name = S.sanitize_html_name( String( d.name || d.id || 'field' ) ); |
| 73 |
const cssNext = S.sanitize_css_classlist( String( d.cssclass || '' ) ); |
| 74 |
|
| 75 |
// Keep wrapper dataset/styles in sync (do NOT assign DOM id to the wrapper). |
| 76 |
if ( el.dataset.html_id !== html_id ) { |
| 77 |
el.dataset.html_id = html_id; |
| 78 |
} |
| 79 |
|
| 80 |
// const prev = el.dataset.cssclass || ''; |
| 81 |
// if ( prev !== cssNext ) { |
| 82 |
// prev.split( /\s+/ ).filter( Boolean ).forEach( (c) => el.classList.remove( c ) ); |
| 83 |
// cssNext.split( /\s+/ ).filter( Boolean ).forEach( (c) => el.classList.add( c ) ); |
| 84 |
// el.dataset.cssclass = cssNext; |
| 85 |
// } |
| 86 |
// NEW: store only. |
| 87 |
if ( 'cssclass' in d ) { |
| 88 |
if ( el.dataset.cssclass !== cssNext ) { |
| 89 |
el.dataset.cssclass = cssNext; |
| 90 |
} |
| 91 |
} |
| 92 |
// Compile template via Base (handles "tmpl-" + caching). |
| 93 |
const tpl = this.get_template( this.template_id ); |
| 94 |
if ( typeof tpl !== 'function' ) { |
| 95 |
_wpbc?.dev?.error?.( 'text_wptpl.tpl.missing', 'Template not found: ' + this.template_id ); |
| 96 |
el.innerHTML = '<div class="wpbc_bfb__error" role="alert">Template not found: wpbc-bfb-field-text.</div>'; |
| 97 |
return; |
| 98 |
} |
| 99 |
|
| 100 |
// Render. Pass sanitized name/html_id back to template data. |
| 101 |
try { |
| 102 |
const tpl_data = { ...d, name, html_id, cssclass: cssNext, default_value: (d.default_value ?? '') }; |
| 103 |
el.innerHTML = tpl( tpl_data ); |
| 104 |
} catch ( e ) { |
| 105 |
_wpbc?.dev?.error?.( 'text_wptpl.tpl.render', e ); |
| 106 |
el.innerHTML = '<div class="wpbc_bfb__error" role="alert">Error rendering field preview.</div>'; |
| 107 |
return; |
| 108 |
} |
| 109 |
|
| 110 |
// Keep wrapper metadata consistent with Base.render(). |
| 111 |
el.dataset.type = d.type || 'text'; |
| 112 |
el.setAttribute( 'data-label', (d.label != null ? String( d.label ) : '') ); |
| 113 |
|
| 114 |
// Normalize a few attributes via the DOM (quotes/newlines), like Base.render(). |
| 115 |
const input = el.querySelector( 'input, textarea, select' ); |
| 116 |
if ( input ) { |
| 117 |
if ( d.placeholder != null ) input.setAttribute( 'placeholder', String( d.placeholder ) ); |
| 118 |
} |
| 119 |
|
| 120 |
// Overlay (handles/toolbars). |
| 121 |
Core.UI?.WPBC_BFB_Overlay?.ensure?.( ctx?.builder, el ); |
| 122 |
} |
| 123 |
|
| 124 |
/** |
| 125 |
* Optional hook executed after field is dropped from the palette. |
| 126 |
* Example recipe placeholder for future: try { if ( !data.name ) { data.name = core.WPBC_BFB_IdService?.next_name?.( 'text' ) || 'text'; } } catch ( e ) { } |
| 127 |
* |
| 128 |
* @param {Object} data Palette/field data. |
| 129 |
* @param {HTMLElement} el Newly created field element. |
| 130 |
* @param {Object} ctx Context { builder, sanit, context: 'drop' | 'load' | 'preview' } |
| 131 |
* @returns {void} |
| 132 |
*/ |
| 133 |
static on_field_drop(data, el, ctx) { |
| 134 |
super.on_field_drop?.( data, el, ctx ); // Required for correctly auto-names from Labels ! |
| 135 |
// (your extra pack-specific logic if ever needed) |
| 136 |
} |
| 137 |
|
| 138 |
} |
| 139 |
|
| 140 |
try { |
| 141 |
Registry.register( 'text', WPBC_BFB_Field_Text ); |
| 142 |
} catch ( e ) { |
| 143 |
_wpbc?.dev?.error?.( 'WPBC_BFB_Field_Text.register_wptpl', e ); |
| 144 |
} |
| 145 |
})( window ); |
| 146 |
|