86ac84e07c
- The settings form and the AJAX section save both went through TMDO_Mode_Manager::set() and dropped its WP_Error: an unsafe jump or a Promotion Guard refusal still said "saved" while the mode stayed put - TMDO_Admin::apply_bridge_modes() returns the refusals; the full form keeps them in a per-user transient and shows them after the redirect, the AJAX save returns them as the error message (the settings JS shows it) - Verify: AdminBridgeModeSaveTest (5 new); unit 709, integration 606, phpcs 0, stan OK - PR: PR-135 (manual F-2)
107 lines
2.7 KiB
JavaScript
107 lines
2.7 KiB
JavaScript
/**
|
|
* WP Data Optimizer — Settings per-section instant save.
|
|
*
|
|
* Each .wpdo-settings-section card has a "儲存此區塊" button that posts only
|
|
* that section's fields via AJAX, updating options without a full page reload.
|
|
*
|
|
* @since 3.0.2
|
|
*/
|
|
/* global wpdoSettings */
|
|
( function () {
|
|
'use strict';
|
|
|
|
if ( typeof wpdoSettings === 'undefined' ) {
|
|
return;
|
|
}
|
|
|
|
const { ajaxUrl, nonce, i18n } = wpdoSettings;
|
|
|
|
/**
|
|
* Collect form fields within a section into a FormData object.
|
|
* Unchecked checkboxes are intentionally omitted (server does isset() ? '1' : '0').
|
|
*
|
|
* @param {HTMLElement} section
|
|
* @returns {FormData}
|
|
*/
|
|
function collectFields( section ) {
|
|
const fd = new FormData();
|
|
section.querySelectorAll( 'input, select, textarea' ).forEach( ( el ) => {
|
|
if ( ! el.name ) {
|
|
return;
|
|
}
|
|
if ( el.type === 'checkbox' ) {
|
|
if ( el.checked ) {
|
|
fd.append( el.name, el.value );
|
|
}
|
|
} else if ( el.type === 'radio' ) {
|
|
if ( el.checked ) {
|
|
fd.append( el.name, el.value );
|
|
}
|
|
} else {
|
|
fd.append( el.name, el.value );
|
|
}
|
|
} );
|
|
return fd;
|
|
}
|
|
|
|
/**
|
|
* Show a transient status message, then fade it out after 2.5s.
|
|
*
|
|
* @param {HTMLElement} statusEl
|
|
* @param {string} message
|
|
* @param {boolean} isError
|
|
*/
|
|
function showStatus( statusEl, message, isError ) {
|
|
statusEl.textContent = message;
|
|
statusEl.style.color = isError ? 'var(--color-error, #b03d3d)' : 'var(--color-success, #5a8c5a)';
|
|
statusEl.classList.add( 'visible' );
|
|
clearTimeout( statusEl._wpdo_timer );
|
|
statusEl._wpdo_timer = setTimeout( () => {
|
|
statusEl.classList.remove( 'visible' );
|
|
}, 2500 );
|
|
}
|
|
|
|
document.addEventListener( 'click', function ( e ) {
|
|
const btn = e.target.closest( '.wpdo-section-save' );
|
|
if ( ! btn ) {
|
|
return;
|
|
}
|
|
const section = btn.closest( '.wpdo-settings-section' );
|
|
const statusEl = btn.nextElementSibling;
|
|
const sectionKey = section ? section.dataset.section : '';
|
|
if ( ! sectionKey ) {
|
|
return;
|
|
}
|
|
|
|
const originalLabel = btn.textContent;
|
|
btn.disabled = true;
|
|
btn.textContent = i18n.saving;
|
|
|
|
const fd = collectFields( section );
|
|
fd.append( 'action', 'wpdo_save_settings_section' );
|
|
fd.append( '_ajax_nonce', nonce );
|
|
fd.append( 'section', sectionKey );
|
|
|
|
fetch( ajaxUrl, {
|
|
method : 'POST',
|
|
credentials : 'same-origin',
|
|
body : fd,
|
|
} )
|
|
.then( ( r ) => r.json() )
|
|
.then( ( data ) => {
|
|
if ( data.success ) {
|
|
showStatus( statusEl, i18n.saved, false );
|
|
} else {
|
|
showStatus( statusEl, ( data.data && data.data.message ) || i18n.error, true );
|
|
}
|
|
} )
|
|
.catch( () => {
|
|
showStatus( statusEl, i18n.error, true );
|
|
} )
|
|
.finally( () => {
|
|
btn.disabled = false;
|
|
btn.textContent = originalLabel;
|
|
} );
|
|
} );
|
|
} )();
|