PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | src/Toolbar/toolbar.js +64 -29 3.1.13.2.1 View file →
@@ -16,8 +16,9 @@
16 16 * so the rounded-frame layout matches what the Agent does to
17 17 * the core admin bar.
18 18 */
19 19 import { isEmbedded } from '@shared/lib/embedded-guard';
20 +import { track } from '@shared/lib/track';
20 21 import { __ } from '@wordpress/i18n';
21 22 import './toolbar.css';
22 23
23 24 const QUICK_EDIT_TOGGLE_EVENT = 'extendify-quick-edit:toggle';
@@ -24,12 +25,22 @@
24 25 const QUICK_EDIT_ON_CLASS = 'extendify-quick-edit-on';
25 26 const AGENT_BTN_HOST_ID = 'wp-admin-bar-extendify-agent-btn';
26 27 const AGENT_SIDEBAR_ID = 'extendify-agent-sidebar';
27 28
29 +function watch(target, options, callback) {
30 + const observer = new MutationObserver(callback);
31 + observer.observe(target, options);
32 + return observer;
33 +}
34 +
28 35 function findExtendifyAgentButton() {
29 36 const host = document.getElementById(AGENT_BTN_HOST_ID);
30 37 if (!host) return null;
31 - return host.querySelector('button') || host;
38 + const mounted = host.querySelector('button:not([disabled])');
39 + if (mounted) return mounted;
40 + // The stand-in never leaves the slot, so a disabled button means not-yet-mounted.
41 + if (host.querySelector('button')) return null;
42 + return host;
32 43 }
33 44
34 45 function clickExtendifyAgent() {
35 46 const btn = findExtendifyAgentButton();
@@ -59,33 +70,45 @@
59 70 * the Zustand store so we don't have to share a chunk with the
60 71 * agent bundle.
61 72 */
62 73 function watchAgentSidebar(toolbar, aiBtn) {
63 - let attached = false;
64 - const observer = new MutationObserver(() => {
65 - const sidebar = document.getElementById(AGENT_SIDEBAR_ID);
66 - if (!sidebar || attached) return;
67 - attached = true;
68 - const update = () => {
69 - const open = !sidebar.hasAttribute('inert');
70 - toolbar.classList.toggle('ext-tb-agent-open', open);
71 - if (!aiBtn) return;
72 - aiBtn.inert = open;
73 - if (open) {
74 - aiBtn.setAttribute('tabindex', '-1');
75 - aiBtn.setAttribute('aria-hidden', 'true');
76 - } else {
77 - aiBtn.removeAttribute('tabindex');
78 - aiBtn.removeAttribute('aria-hidden');
74 + const setOpen = (open) => {
75 + toolbar.classList.toggle('ext-tb-agent-open', open);
76 + if (!aiBtn) return;
77 + aiBtn.inert = open;
78 + if (open) {
79 + aiBtn.setAttribute('tabindex', '-1');
80 + aiBtn.setAttribute('aria-hidden', 'true');
81 + } else {
82 + aiBtn.removeAttribute('tabindex');
83 + aiBtn.removeAttribute('aria-hidden');
84 + }
85 + };
86 + // A resize past the mobile breakpoint replaces this node, so never latch on one.
87 + let watched = null;
88 + let inertObserver = null;
89 + const observer = watch(
90 + document.body,
91 + { childList: true, subtree: true },
92 + () => {
93 + const sidebar = document.getElementById(AGENT_SIDEBAR_ID);
94 + if (sidebar === watched) return;
95 + watched = sidebar;
96 + inertObserver?.disconnect();
97 + inertObserver = null;
98 + if (!sidebar) {
99 + setOpen(false);
100 + return;
79 101 }
80 - };
81 - new MutationObserver(update).observe(sidebar, {
82 - attributes: true,
83 - attributeFilter: ['inert'],
84 - });
85 - update();
86 - });
87 - observer.observe(document.body, { childList: true, subtree: true });
102 + const update = () => setOpen(!sidebar.hasAttribute('inert'));
103 + inertObserver = watch(
104 + sidebar,
105 + { attributes: true, attributeFilter: ['inert'] },
106 + update,
107 + );
108 + update();
109 + },
110 + );
88 111 if (document.getElementById(AGENT_SIDEBAR_ID)) observer.takeRecords();
89 112 }
90 113
91 114 /**
@@ -98,12 +121,13 @@
98 121 const on = document.documentElement.classList.contains(QUICK_EDIT_ON_CLASS);
99 122 btn.setAttribute('aria-checked', on ? 'true' : 'false');
100 123 };
101 124 sync();
102 - new MutationObserver(sync).observe(document.documentElement, {
103 - attributes: true,
104 - attributeFilter: ['class'],
105 - });
125 + watch(
126 + document.documentElement,
127 + { attributes: true, attributeFilter: ['class'] },
128 + sync,
129 + );
106 130 }
107 131
108 132 function init() {
109 133 // Don't wire the toolbar inside another tool's iframe (Customizer preview,
@@ -144,8 +168,19 @@
144 168 e.preventDefault();
145 169 window.dispatchEvent(new CustomEvent(QUICK_EDIT_TOGGLE_EVENT));
146 170 });
147 171 }
172 +
173 + toolbar
174 + .querySelector('.ext-tb-edit')
175 + ?.addEventListener('click', () =>
176 + track('toolbar_link_clicked', { target: 'block_editor' }),
177 + );
178 + toolbar
179 + .querySelector('.ext-tb-admin-link')
180 + ?.addEventListener('click', () =>
181 + track('toolbar_link_clicked', { target: 'wp_admin' }),
182 + );
148 183
149 184 watchAgentSidebar(toolbar, aiBtn);
150 185 }
151 186