File: /home/d5123/myboofola_com/wp-content/plugins/extendify/src/Toolbar/toolbar.js
/**
* Simple toolbar bootstrap.
*
* Vanilla JS bound to the bar that `Frontend::render()` writes at
* `wp_body_open`. Three integrations:
*
* - "AI Agent" button → drives the Extendify Agent's mounted
* admin-bar button (the bar is hidden via CSS but stays in the
* DOM so the Agent's React code can still target it).
* - "Quick Edit" toggle → dispatches a custom event the Quick Edit
* bootstrap listens for. Aria-checked mirrors the
* `extendify-quick-edit-on` class on `<html>` so the toggle
* reflects state changes from any source (admin-bar pill,
* chat-input "Select" button, etc.).
* - When the Agent sidebar opens, the toolbar slides next to it
* so the rounded-frame layout matches what the Agent does to
* the core admin bar.
*/
import { isEmbedded } from '@shared/lib/embedded-guard';
import { __ } from '@wordpress/i18n';
import './toolbar.css';
const QUICK_EDIT_TOGGLE_EVENT = 'extendify-quick-edit:toggle';
const QUICK_EDIT_ON_CLASS = 'extendify-quick-edit-on';
const AGENT_BTN_HOST_ID = 'wp-admin-bar-extendify-agent-btn';
const AGENT_SIDEBAR_ID = 'extendify-agent-sidebar';
function findExtendifyAgentButton() {
const host = document.getElementById(AGENT_BTN_HOST_ID);
if (!host) return null;
return host.querySelector('button') || host;
}
function clickExtendifyAgent() {
const btn = findExtendifyAgentButton();
if (btn) {
btn.click();
return true;
}
return false;
}
function waitFor(predicate, maxTries, intervalMs) {
return new Promise((resolve, reject) => {
let tries = 0;
const tick = () => {
if (predicate()) return resolve();
if (++tries >= maxTries) return reject();
setTimeout(tick, intervalMs);
};
tick();
});
}
/**
* When the Agent sidebar opens we want the toolbar to slide next
* to it (matches how the Agent reframes the core admin bar). We
* watch the sidebar's `inert` attribute rather than subscribing to
* the Zustand store so we don't have to share a chunk with the
* agent bundle.
*/
function watchAgentSidebar(toolbar, aiBtn) {
let attached = false;
const observer = new MutationObserver(() => {
const sidebar = document.getElementById(AGENT_SIDEBAR_ID);
if (!sidebar || attached) return;
attached = true;
const update = () => {
const open = !sidebar.hasAttribute('inert');
toolbar.classList.toggle('ext-tb-agent-open', open);
if (!aiBtn) return;
aiBtn.inert = open;
if (open) {
aiBtn.setAttribute('tabindex', '-1');
aiBtn.setAttribute('aria-hidden', 'true');
} else {
aiBtn.removeAttribute('tabindex');
aiBtn.removeAttribute('aria-hidden');
}
};
new MutationObserver(update).observe(sidebar, {
attributes: true,
attributeFilter: ['inert'],
});
update();
});
observer.observe(document.body, { childList: true, subtree: true });
if (document.getElementById(AGENT_SIDEBAR_ID)) observer.takeRecords();
}
/**
* Mirror Quick Edit's `extendify-quick-edit-on` html-class onto
* `aria-checked` so the visual toggle reflects state changes from
* any source (admin-bar pill, chat input Select button, …).
*/
function watchQuickEditState(btn) {
const sync = () => {
const on = document.documentElement.classList.contains(QUICK_EDIT_ON_CLASS);
btn.setAttribute('aria-checked', on ? 'true' : 'false');
};
sync();
new MutationObserver(sync).observe(document.documentElement, {
attributes: true,
attributeFilter: ['class'],
});
}
function init() {
// Don't wire the toolbar inside another tool's iframe (Customizer preview,
// page-builder previews). The server skips rendering it there too.
if (isEmbedded()) return;
const toolbar = document.getElementById('extendify-toolbar');
if (!toolbar) return;
const aiBtn = document.getElementById('ext-tb-ai-agent');
const quickBtn = document.getElementById('ext-tb-quick-edit');
if (aiBtn) {
aiBtn.disabled = true;
aiBtn.title = __('Loading…', 'extendify-local');
aiBtn.setAttribute('aria-busy', 'true');
waitFor(findExtendifyAgentButton, 100, 50).then(
() => {
aiBtn.disabled = false;
aiBtn.removeAttribute('title');
aiBtn.setAttribute('aria-busy', 'false');
},
() => {
aiBtn.title = __('AI Agent unavailable', 'extendify-local');
aiBtn.setAttribute('aria-busy', 'false');
},
);
aiBtn.addEventListener('click', (e) => {
e.preventDefault();
if (!clickExtendifyAgent()) {
waitFor(findExtendifyAgentButton, 20, 50).then(clickExtendifyAgent);
}
});
}
if (quickBtn) {
watchQuickEditState(quickBtn);
quickBtn.addEventListener('click', (e) => {
e.preventDefault();
window.dispatchEvent(new CustomEvent(QUICK_EDIT_TOGGLE_EVENT));
});
}
watchAgentSidebar(toolbar, aiBtn);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}