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 / section / _src / bfb-inspector-patches.js

bfb-inspector-patches.js in Booking Calendar 11.2, at includes/page-form-builder/field-packs/section/_src/bfb-inspector-patches.js

247 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Inspector Patches / Glue for Section:
3 * ---------------------------------------------------------------------------------
4 * 1) Prevent full re-render when changing "columns" for .wpbc_bfb__section
5 * 2) Bind inspector to:
6 * - Mount "layout_chips" slot
7 * - Keep numeric "columns" input stable & debounced
8 * - Observe live DOM column changes and sync inspector
9 * - Mount/refresh "column_styles" slot exposed by UI.wpbc_bfb_column_styles
10 *
11 * == File: /includes/page-form-builder/field-packs/section/_out/bfb-inspector-patches.js
12 *
13 * @since 11.0.0
14 * @modified 2025-09-16 11:26
15 * @version 1.0.0
16 */
17 (function ( w ) {
18 'use strict';
19
20 var Core = ( w.WPBC_BFB_Core = w.WPBC_BFB_Core || {} );
21 var UI = ( Core.UI = Core.UI || {} );
22
23 var H = Core.WPBC_Form_Builder_Helper || {};
24 var DOM = ( Core.WPBC_BFB_DOM && Core.WPBC_BFB_DOM.SELECTORS ) || {
25 row : '.wpbc_bfb__row',
26 column : '.wpbc_bfb__column'
27 };
28
29 /**
30 * Read actual number of columns from DOM.
31 *
32 * @param {HTMLElement} el
33 * @returns {number}
34 */
35 function dom_cols( el ) {
36 try {
37 var row = el ? el.querySelector( ':scope > ' + DOM.row ) : null;
38 var cnt = row ? row.querySelectorAll( ':scope > ' + DOM.column ).length : 1;
39 var clamp = Core.WPBC_BFB_Sanitize && Core.WPBC_BFB_Sanitize.clamp ? Core.WPBC_BFB_Sanitize.clamp : function ( n, a, b ) { return Math.max( a, Math.min( b, n ) ); };
40 return clamp( Number( cnt ) || 1, 1, 4 );
41 } catch ( _e ) {
42 return 1;
43 }
44 }
45
46 /**
47 * Observe column DOM changes to keep inspector inputs in sync.
48 *
49 * @param {object} builder
50 * @param {HTMLElement} section_el
51 * @param {HTMLElement} inspector_root
52 * @returns {Function} disconnect
53 */
54 function observe_cols( builder, section_el, inspector_root ) {
55 var row = section_el && section_el.querySelector( ':scope > ' + DOM.row );
56 if ( ! row ) { return function () {}; }
57
58 var input = inspector_root && inspector_root.querySelector( 'input[data-inspector-key="columns"]' );
59 var mo = new MutationObserver( function () {
60 var cnt = dom_cols( section_el );
61 if ( input && input.value !== String( cnt ) ) {
62 input.value = String( cnt );
63 // Fire an input event so len-control syncs the slider too.
64 try { input.dispatchEvent( new Event('input', { bubbles: true }) ); } catch (_e) {}
65 }
66 inspector_root && inspector_root.setAttribute( 'data-bfb-section-cols', String( cnt ) );
67 section_el.dataset.columns = String( cnt );
68
69 // Also refresh column styles if present.
70 if ( UI && UI.wpbc_bfb_column_styles && typeof UI.wpbc_bfb_column_styles.refresh_for_section === 'function' ) {
71 UI.wpbc_bfb_column_styles.refresh_for_section( builder, section_el, inspector_root );
72 }
73 } );
74 try { mo.observe( row, { childList : true } ); } catch ( _err ) {}
75 return function unobserve() { try { mo.disconnect(); } catch ( _e ) {} };
76 }
77
78 /**
79 * Ensure host for layout chips stays stable.
80 *
81 * @param {HTMLElement} inspector_root
82 * @returns {HTMLElement|null}
83 */
84 function ensure_chips_host( inspector_root ) {
85 if ( ! inspector_root ) { return null; }
86 var host = inspector_root.querySelector( '[data-bfb-slot="layout_chips"]' )
87 || inspector_root.querySelector( '.inspector__row--layout-chips .wpbc_bfb__layout_chips' )
88 || inspector_root.querySelector( '#wpbc_bfb__layout_chips_host' );
89 if ( host ) {
90 host.classList.add( 'wpbc_bfb__layout_chips' );
91 host.setAttribute( 'data-bfb-slot', 'layout_chips' );
92 }
93 return host;
94 }
95
96 /**
97 * Render layout chips into inspector, if available.
98 *
99 * @param {object} builder
100 * @param {HTMLElement} section_el
101 * @param {HTMLElement} inspector_root
102 */
103 function render_chips_into_inspector( builder, section_el, inspector_root ) {
104 if ( ! UI.WPBC_BFB_Layout_Chips || typeof UI.WPBC_BFB_Layout_Chips.render_for_section !== 'function' ) { return; }
105 var host = ensure_chips_host( inspector_root );
106 if ( ! host ) { return; }
107 host.innerHTML = '';
108 UI.WPBC_BFB_Layout_Chips.render_for_section( builder, section_el, host );
109 }
110
111 // ------------------------------------------------------------------------------------------------
112 // 1) Patch: prevent full re-render for columns change (section only)
113 // ------------------------------------------------------------------------------------------------
114 (function patch_no_rerender_for_columns() {
115 var Inspector = w.WPBC_BFB_Inspector;
116 if ( ! Inspector || Inspector.__wpbc_no_rerender_columns ) { return; }
117 Inspector.__wpbc_no_rerender_columns = true;
118
119 var orig = Inspector.prototype._needs_rerender;
120 Inspector.prototype._needs_rerender = function ( el, key, e ) {
121 if ( el && el.classList && el.classList.contains( 'wpbc_bfb__section' ) && key === 'columns' ) {
122 return false;
123 }
124 return ( typeof orig === 'function' ) ? orig.call( this, el, key, e ) : false;
125 };
126 })();
127
128 // ------------------------------------------------------------------------------------------------
129 // 2) Patch: extend Inspector.bind_to_field to wire chips + columns input + column styles slot
130 // ------------------------------------------------------------------------------------------------
131 function patch_inspector_bind_once() {
132 var Inspector = w.WPBC_BFB_Inspector;
133 if ( ! Inspector || Inspector.__wpbc_section_bind_patched ) { return; }
134 if ( ! Inspector.prototype || ! Inspector.prototype.bind_to_field ) { return; }
135 Inspector.__wpbc_section_bind_patched = true;
136
137 var orig_bind = Inspector.prototype.bind_to_field;
138
139 Inspector.prototype.bind_to_field = function ( el ) {
140 orig_bind.call( this, el );
141
142 try {
143 var ins = this.panel || document.getElementById( 'wpbc_bfb__inspector' ) || document.querySelector( '.wpbc_bfb__inspector' );
144 var builder = this.builder || w.wpbc_bfb || null;
145 if ( ! ins || ! builder || !( el && el.classList && el.classList.contains( 'wpbc_bfb__section' ) ) ) { return; }
146
147
148 // Layout chips.
149 render_chips_into_inspector( builder, el, ins );
150
151 // Stable numeric "columns" input behavior.
152 var input = ins.querySelector( 'input[data-inspector-key="columns"]' );
153 if ( input && ! input.__wpbc_cols_hooked ) {
154 input.__wpbc_cols_hooked = true;
155 input.value = String( dom_cols( el ) );
156
157 var apply_change = function () {
158 var desired = ( Core.WPBC_BFB_Sanitize && Core.WPBC_BFB_Sanitize.clamp )
159 ? Core.WPBC_BFB_Sanitize.clamp( input.value | 0, 1, 4 )
160 : Math.max( 1, Math.min( 4, Number( input.value ) || 1 ) );
161 var current = dom_cols( el );
162 if ( desired === current ) { return; }
163
164 if ( typeof builder.set_section_columns === 'function' ) {
165 builder.set_section_columns( el, desired );
166 }
167 el.dataset.columns = String( desired );
168 ins.setAttribute( 'data-bfb-section-cols', String( desired ) );
169
170 // Refresh column styles UI on column count change.
171 if ( UI && UI.wpbc_bfb_column_styles && typeof UI.wpbc_bfb_column_styles.refresh_for_section === 'function' ) {
172 UI.wpbc_bfb_column_styles.refresh_for_section( builder, el, ins );
173 }
174 };
175
176 var debounced = ( H && H.debounce ) ? H.debounce( apply_change, 120 ) : apply_change;
177 input.addEventListener( 'input', debounced );
178 input.addEventListener( 'change', apply_change );
179 }
180
181 // Observe DOM changes in columns (sync inspector).
182 if ( this.__wpbc_cols_unobserve ) {
183 try { this.__wpbc_cols_unobserve(); } catch ( _e ) {}
184 this.__wpbc_cols_unobserve = null;
185 }
186 this.__wpbc_cols_unobserve = observe_cols( builder, el, ins );
187
188 // Mount reusable "column_styles" slot into the inspector, if available.
189 if ( UI && UI.wpbc_bfb_column_styles && typeof UI.wpbc_bfb_column_styles.render_for_section === 'function' ) {
190 UI.wpbc_bfb_column_styles.render_for_section( builder, el, ins.querySelector( '[data-bfb-slot="column_styles"]' ) );
191 }
192
193 // Keep both slots fresh on structure events.
194 var EV = Core.WPBC_BFB_Events || {};
195 var refresh = () => {
196 var cur = builder.get_selected_field && builder.get_selected_field();
197 if ( ! cur || ! cur.classList || ! cur.classList.contains( 'wpbc_bfb__section' ) ) { return; }
198 render_chips_into_inspector( builder, cur, ins );
199 if ( UI && UI.wpbc_bfb_column_styles && typeof UI.wpbc_bfb_column_styles.refresh_for_section === 'function' ) {
200 UI.wpbc_bfb_column_styles.refresh_for_section( builder, cur, ins );
201 }
202 var c = dom_cols( cur );
203 ins.setAttribute( 'data-bfb-section-cols', String( c ) );
204 var inp = ins.querySelector( 'input[data-inspector-key="columns"]' );
205 if ( inp ) { inp.value = String( c ); }
206 };
207
208 if ( ! this.__wpbc_cols_bus_hooked && builder.bus ) {
209 this.__wpbc_cols_bus_hooked = true;
210 builder.bus.on && builder.bus.on( EV.FIELD_ADD, refresh );
211 builder.bus.on && builder.bus.on( EV.FIELD_REMOVE, refresh );
212 builder.bus.on && builder.bus.on( EV.STRUCTURE_LOADED, refresh );
213 builder.bus.on && builder.bus.on( EV.STRUCTURE_CHANGE, function (ev) {
214 // The bus gives a DOM CustomEvent → data is in ev.detail. But be defensive in case some callers pass a plain object.
215 var d = ev && (ev.detail || ev);
216 var src = d && d.source;
217 // Skip re-render when only per-column styles changed.
218 if ( src === 'column_styles' || src === 'column_styles_reset' ) {
219 // Optional: keep the "columns" input value in sync without re-rendering.
220 try {
221 var cur = builder.get_selected_field && builder.get_selected_field();
222 if ( cur && cur.classList && cur.classList.contains( 'wpbc_bfb__section' ) ) {
223 var c = dom_cols( cur );
224 ins.setAttribute( 'data-bfb-section-cols', String( c ) );
225 var inp = ins.querySelector( 'input[data-inspector-key="columns"]' );
226 if ( inp ) {
227 inp.value = String( c );
228 }
229 }
230 } catch ( _e ) {}
231 return;
232 }
233 refresh();
234 } );
235 }
236
237 } catch ( e ) {
238 w._wpbc && w._wpbc.dev && w._wpbc.dev.error && w._wpbc.dev.error( 'section_inspector.patch_bind', e );
239 }
240 };
241 }
242
243 patch_inspector_bind_once();
244 document.addEventListener( 'wpbc_bfb_inspector_ready', patch_inspector_bind_once );
245
246 })( window );
247