fix wpcfto select and repeater related visibility and validation

This commit is contained in:
dwindown
2025-08-29 19:27:50 +07:00
parent ccb2b1aea1
commit 255da46509
14 changed files with 495 additions and 233 deletions

View File

@@ -11,7 +11,8 @@ Vue.component('wpcfto_select', {
dropdownOpen: false,
// local reactive copy so we don't mutate props
localOptions: {}, // {value: label}
localSearchable: false
localSearchable: false,
runtimeSubmenuClass: ''
};
},
computed: {
@@ -68,6 +69,48 @@ Vue.component('wpcfto_select', {
this.localSearchable = !!(this.fields && this.fields.searchable);
this.value = this.field_value;
// Attach submenu section class expected by initSubmenu()
let submenuClass, slug;
try {
const tabEl = this.$el.closest('.wpcfto-tab');
const tabId = tabEl && tabEl.getAttribute ? tabEl.getAttribute('id') : null;
const raw = (this.fields && this.fields.submenu) ? String(this.fields.submenu) : '';
slug = raw.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
// initSubmenu() expects classes like `${tabId}_${slug}`
submenuClass = tabId ? (tabId + '_' + slug) : slug;
if (submenuClass) {
this.runtimeSubmenuClass = submenuClass;
}
} catch (e) {}
// Ensure submenu discovery works even if initSubmenu ran before this component mounted
try {
const active = document.querySelector('.wpcfto-submenus .active');
const activeKey = active ? active.getAttribute('data-submenu') : null;
if (submenuClass) {
// Also set data-submenu attr for selectors that rely on attributes
this.$el.setAttribute('data-submenu', submenuClass);
// if (activeKey && (activeKey === submenuClass || activeKey === slug)) {
// this.$el.style.removeProperty('display');
// this.$el.style.removeProperty('visibility');
// }
// no direct style changes; visibility is handled by initSubmenu()
}
} catch (e) {}
// Listen for submenu changes to unhide this field when needed
try {
this.__onSubmenuClick = (ev) => {
const btn = ev.target.closest('[data-submenu]');
if (!btn) return;
const key = btn.getAttribute('data-submenu');
if (key && submenuClass && (key === submenuClass || key === slug)) {
// nothing needed; class binding ensures we have the right class and initSubmenu will reveal us
}
};
document.addEventListener('click', this.__onSubmenuClick, true);
} catch (e) {}
// Register for external control (optional but handy)
try {
window.wpcftoSelectRegistry = window.wpcftoSelectRegistry || {};
@@ -77,6 +120,10 @@ Vue.component('wpcfto_select', {
document.addEventListener('click', this.handleClickOutside);
},
beforeDestroy() {
if (this.__onSubmenuClick) {
try { document.removeEventListener('click', this.__onSubmenuClick, true); } catch(e) {}
this.__onSubmenuClick = null;
}
document.removeEventListener('click', this.handleClickOutside);
if (window.wpcftoSelectRegistry) {
delete window.wpcftoSelectRegistry[this.field_id];
@@ -162,7 +209,10 @@ Vue.component('wpcfto_select', {
}
},
template: `
<div class="wpcfto_generic_field wpcfto_generic_field__select" :class="{ open: dropdownOpen }" :data-field="field_id">
<div
class="wpcfto_generic_field wpcfto_generic_field_select"
:class="['columns-' + (fields && fields.columns ? fields.columns : 1), runtimeSubmenuClass, { open: dropdownOpen }]"
:data-field="field_id">
<wpcfto_fields_aside_before :fields="fields" :field_label="field_label" :required="fields.required === true"></wpcfto_fields_aside_before>