Files
wpdev d36bb954d1 chore: initial snapshot of 2meet-data-optimizer v0.1.0
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
2026-07-31 05:06:36 +08:00

247 lines
5.8 KiB
JavaScript

/**
* WP Data Optimizer — Admin JS (native fetch, no jQuery)
*
* @package WP_Data_Optimizer
*/
( function () {
'use strict';
var WPDO = window.wpdoAdmin || {};
var i18n = WPDO.i18n || {};
document.addEventListener(
'DOMContentLoaded',
function () {
bindFlushCacheButtons();
bindStatusRefresh();
}
);
/**
* Announce a message via the shared aria-live region.
* Falls back to creating the region on first call.
*/
function announce( message ) {
var region = document.getElementById( 'wpdo-aria-live' );
if ( ! region ) {
region = document.createElement( 'div' );
region.id = 'wpdo-aria-live';
region.className = 'wpdo-sr-only';
region.setAttribute( 'role', 'status' );
region.setAttribute( 'aria-live', 'polite' );
region.setAttribute( 'aria-atomic', 'true' );
document.body.appendChild( region );
}
region.textContent = '';
setTimeout(
function () {
region.textContent = message; },
50
);
}
/**
* Render an inline admin notice at the top of .wpdo-wrap.
* Dismissable by user. Replaces legacy alert() for errors.
*/
function showNotice( message, type ) {
type = type || 'error';
var wrap = document.querySelector( '.wpdo-wrap' );
if ( ! wrap ) {
return;
}
var notice = document.createElement( 'div' );
notice.className = 'notice notice-' + type + ' is-dismissible';
notice.setAttribute( 'role', type === 'error' ? 'alert' : 'status' );
var p = document.createElement( 'p' );
p.textContent = message;
notice.appendChild( p );
var dismiss = document.createElement( 'button' );
dismiss.type = 'button';
dismiss.className = 'notice-dismiss';
dismiss.setAttribute( 'aria-label', i18n.dismiss || 'Dismiss' );
dismiss.addEventListener(
'click',
function () {
notice.remove();
}
);
notice.appendChild( dismiss );
// Insert after the H1 so it appears at the top of the content area.
var h1 = wrap.querySelector( 'h1' );
if ( h1 && h1.nextSibling ) {
wrap.insertBefore( notice, h1.nextSibling );
} else {
wrap.prepend( notice );
}
announce( message );
}
/**
* POST to admin-ajax.php using native fetch + FormData.
* Returns a Promise resolving to the parsed JSON response.
*/
function wpdoAjax( actionType, data ) {
var body = new FormData();
body.append( 'action', 'wpdo_admin_action' );
body.append( 'nonce', WPDO.nonce || '' );
body.append( 'action_type', actionType );
Object.keys( data || {} ).forEach(
function ( key ) {
body.append( key, data[ key ] );
}
);
return fetch(
WPDO.ajaxUrl,
{
method: 'POST',
credentials: 'same-origin',
body: body,
}
)
.then(
function ( res ) {
if ( ! res.ok ) {
throw new Error( 'HTTP ' + res.status );
}
return res.json();
}
);
}
/**
* Flush cache button handler — delegated click listener.
*/
function bindFlushCacheButtons() {
document.addEventListener(
'click',
function ( e ) {
var btn = e.target.closest( '.wpdo-flush-cache' );
if ( ! btn ) {
return;
}
e.preventDefault();
var postType = btn.getAttribute( 'data-post-type' );
if ( ! postType ) {
return;
}
var originalLabel = btn.textContent;
btn.disabled = true;
btn.textContent = i18n.flushing || 'Flushing…';
announce( btn.textContent );
wpdoAjax( 'flush_cache', { post_type: postType } )
.then(
function ( response ) {
if ( response && response.success ) {
btn.textContent = i18n.flushed || 'Flushed!';
announce( btn.textContent );
setTimeout(
function () {
btn.disabled = false;
btn.textContent = i18n.flushLabel || originalLabel;
},
2000
);
} else {
btn.disabled = false;
btn.textContent = i18n.flushLabel || originalLabel;
var msg = ( response && response.data ) ? String( response.data ) : ( i18n.error || 'Unknown error' );
showNotice( msg, 'error' );
}
}
)
.catch(
function () {
btn.disabled = false;
btn.textContent = i18n.flushLabel || originalLabel;
showNotice( i18n.error || 'Request failed.', 'error' );
}
);
}
);
}
/**
* Auto-refresh module status on the Dashboard tab (every 30s).
*/
function bindStatusRefresh() {
var isDashboard = document.querySelector( '.wpdo-wrap' )
&& window.location.search.indexOf( 'tab=dashboard' ) !== -1;
if ( ! isDashboard ) {
return;
}
var timer = setInterval(
function () {
if ( ! document.hidden ) {
refreshStatus();
}
},
30000
);
window.addEventListener(
'beforeunload',
function () {
clearInterval( timer );
}
);
}
function refreshStatus() {
wpdoAjax( 'module_status', {} )
.then(
function ( response ) {
if ( ! response || ! response.success || ! response.data ) {
return;
}
var data = response.data;
var changed = 0;
var changedSummaries = [];
document.querySelectorAll( '.wpdo-state' ).forEach(
function ( el ) {
var row = el.closest( 'tr' );
var codeEl = row ? row.querySelector( 'code' ) : null;
if ( ! codeEl ) {
return;
}
var module = codeEl.textContent;
if ( ! module || ! ( module in data ) ) {
return;
}
var newState = data[ module ];
if ( el.textContent === newState ) {
return;
}
el.textContent = newState;
el.className = 'wpdo-state wpdo-state-' + newState;
changed++;
changedSummaries.push( module + ' → ' + newState );
}
);
if ( changed > 0 ) {
announce( changedSummaries.join( '、' ) );
}
}
)
.catch(
function () {
// Fail silently on polling — user will see the stale state; not worth a notice.
}
);
}
} )();