Skip to content

Commit 43ca59f

Browse files
tdwhite0claude
andcommitted
add Universal Editor debug instrumentation
Adds event listeners for all UE events (content-add, content-details, content-move, content-patch, content-remove, content-update, ui-preview, ui-edit, ui-viewport-change, initialized) with color-coded console logging. Auto-detects UE context or can be forced with ?ue-debug=true parameter. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d20ae81 commit 43ca59f

File tree

6 files changed

+335
-17
lines changed

6 files changed

+335
-17
lines changed

blocks/tabs/tabs.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ export default function decorate(block) {
77
tabContent.className = 'tabs-content';
88

99
[...block.children].forEach((item, index) => {
10-
const tabNameDiv = item.children[0];
11-
const contentDiv = item.children[1];
10+
const children = [...item.children];
11+
const tabNameDiv = children[0];
12+
const contentDivs = children.slice(1);
1213

1314
const tabName = tabNameDiv?.textContent?.trim() || `Tab ${index + 1}`;
14-
const tabId = `tab-${index}`;
15-
const panelId = `panel-${index}`;
15+
const tabId = `tab-${block.id || 'tabs'}-${index}`;
16+
const panelId = `panel-${block.id || 'tabs'}-${index}`;
1617

1718
// Create tab button
1819
const tab = document.createElement('button');
@@ -33,9 +34,17 @@ export default function decorate(block) {
3334
panel.setAttribute('aria-labelledby', tabId);
3435
panel.setAttribute('id', panelId);
3536
panel.hidden = index !== 0;
36-
if (contentDiv) {
37-
panel.innerHTML = contentDiv.innerHTML;
38-
}
37+
38+
// Append all content divs to the panel
39+
contentDivs.forEach((contentDiv) => {
40+
if (contentDiv) {
41+
// Move the content (preserves nested blocks/components)
42+
while (contentDiv.firstChild) {
43+
panel.append(contentDiv.firstChild);
44+
}
45+
}
46+
});
47+
3948
tabContent.append(panel);
4049
});
4150

component-definition.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@
392392
}
393393
},
394394
{
395-
"title": "Tabs Item",
395+
"title": "Tab",
396396
"id": "tabs-item",
397397
"plugins": {
398398
"xwalk": {
@@ -401,8 +401,8 @@
401401
"template": {
402402
"name": "Tab",
403403
"model": "tabs-item",
404-
"tabName": "Tab Name",
405-
"content": "<p>Lorem Ipsum</p>"
404+
"filter": "tabs-item",
405+
"tabName": "Tab Name"
406406
}
407407
}
408408
}

component-filters.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@
109109
"tabs-item"
110110
]
111111
},
112+
{
113+
"id": "tabs-item",
114+
"components": [
115+
"text",
116+
"image",
117+
"button",
118+
"title"
119+
]
120+
},
112121
{
113122
"id": "video",
114123
"components": []

component-models.json

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,6 @@
532532
"name": "tabName",
533533
"value": "",
534534
"label": "Tab Name"
535-
},
536-
{
537-
"component": "richtext",
538-
"name": "content",
539-
"value": "",
540-
"label": "Content",
541-
"valueType": "string"
542535
}
543536
]
544537
},

scripts/delayed.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
// add delayed functionality here
2+
3+
// Load Universal Editor debug instrumentation
4+
// This will auto-detect if running in Universal Editor context
5+
// or can be forced with ?ue-debug=true URL parameter
6+
import('./ue-debug.js');

scripts/ue-debug.js

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/**
2+
* Universal Editor Debug Instrumentation
3+
* Logs all Universal Editor events for debugging and development purposes.
4+
*
5+
* Events documented at:
6+
* https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/developing/universal-editor/events
7+
*/
8+
9+
const UE_DEBUG_PREFIX = '[UE Debug]';
10+
11+
/**
12+
* Style configurations for console logging
13+
*/
14+
const LOG_STYLES = {
15+
event: 'color: #2196F3; font-weight: bold;',
16+
content: 'color: #4CAF50; font-weight: bold;',
17+
ui: 'color: #FF9800; font-weight: bold;',
18+
data: 'color: #9C27B0;',
19+
timestamp: 'color: #757575; font-style: italic;',
20+
error: 'color: #F44336; font-weight: bold;',
21+
};
22+
23+
/**
24+
* Get current timestamp for logging
25+
* @returns {string} Formatted timestamp
26+
*/
27+
function getTimestamp() {
28+
return new Date().toISOString().split('T')[1].slice(0, -1);
29+
}
30+
31+
/**
32+
* Log event with formatted output
33+
* @param {string} eventName - Name of the event
34+
* @param {string} category - Event category (content/ui)
35+
* @param {Object} detail - Event detail payload
36+
*/
37+
function logEvent(eventName, category, detail) {
38+
const style = category === 'content' ? LOG_STYLES.content : LOG_STYLES.ui;
39+
40+
console.group(
41+
`%c${UE_DEBUG_PREFIX} %c${eventName} %c@ ${getTimestamp()}`,
42+
LOG_STYLES.event,
43+
style,
44+
LOG_STYLES.timestamp,
45+
);
46+
47+
if (detail && Object.keys(detail).length > 0) {
48+
console.log('%cPayload:', LOG_STYLES.data, detail);
49+
50+
// Log specific detail properties for easier debugging
51+
if (detail.resource) {
52+
console.log(' Resource:', detail.resource);
53+
}
54+
if (detail.updates) {
55+
console.log(' Updates:', detail.updates);
56+
}
57+
if (detail.content) {
58+
console.log(' Content:', detail.content);
59+
}
60+
if (detail.model) {
61+
console.log(' Model:', detail.model);
62+
}
63+
if (detail.patch) {
64+
console.log(' Patch:', detail.patch);
65+
}
66+
if (detail.request) {
67+
console.log(' Request:', detail.request);
68+
}
69+
if (detail.response) {
70+
console.log(' Response:', detail.response);
71+
}
72+
if (detail.from) {
73+
console.log(' From:', detail.from);
74+
}
75+
if (detail.to) {
76+
console.log(' To:', detail.to);
77+
}
78+
if (detail.before) {
79+
console.log(' Before:', detail.before);
80+
}
81+
if (detail.value !== undefined) {
82+
console.log(' Value:', detail.value);
83+
}
84+
if (detail.viewport) {
85+
console.log(' Viewport:', detail.viewport);
86+
}
87+
if (detail.width !== undefined || detail.height !== undefined) {
88+
console.log(' Dimensions:', { width: detail.width, height: detail.height });
89+
}
90+
} else {
91+
console.log('%cNo payload (empty event)', LOG_STYLES.timestamp);
92+
}
93+
94+
console.groupEnd();
95+
}
96+
97+
/**
98+
* Create event listener for a specific UE event
99+
* @param {string} eventName - Name of the event to listen for
100+
* @param {string} category - Event category for logging
101+
* @returns {Function} Event handler function
102+
*/
103+
function createEventListener(eventName, category) {
104+
return (event) => {
105+
logEvent(eventName, category, event.detail);
106+
};
107+
}
108+
109+
/**
110+
* Universal Editor Content Events
111+
* These events are triggered when content is modified in the editor
112+
*/
113+
const CONTENT_EVENTS = [
114+
{
115+
name: 'aue:content-add',
116+
description: 'Triggered when a new component is added to a container',
117+
},
118+
{
119+
name: 'aue:content-details',
120+
description: 'Triggered when a component is loaded in the properties panel',
121+
},
122+
{
123+
name: 'aue:content-move',
124+
description: 'Triggered when a component is moved',
125+
},
126+
{
127+
name: 'aue:content-patch',
128+
description: 'Triggered when component data is updated in properties panel',
129+
},
130+
{
131+
name: 'aue:content-remove',
132+
description: 'Triggered when a component is removed from a container',
133+
},
134+
{
135+
name: 'aue:content-update',
136+
description: 'Triggered when component properties are updated in-context',
137+
},
138+
];
139+
140+
/**
141+
* Universal Editor UI Events
142+
* These events are triggered when the editor UI state changes
143+
*/
144+
const UI_EVENTS = [
145+
{
146+
name: 'aue:ui-preview',
147+
description: 'Triggered when the editing mode changes to Preview',
148+
},
149+
{
150+
name: 'aue:ui-edit',
151+
description: 'Triggered when the editing mode changes to Edit',
152+
},
153+
{
154+
name: 'aue:ui-viewport-change',
155+
description: 'Triggered when viewport size is changed',
156+
},
157+
{
158+
name: 'aue:initialized',
159+
description: 'Notifies the remote page it loaded successfully in the Universal Editor',
160+
},
161+
];
162+
163+
/**
164+
* Track event counts for summary reporting
165+
*/
166+
const eventCounts = {};
167+
168+
/**
169+
* Create event listener with count tracking
170+
* @param {string} eventName - Name of the event
171+
* @param {string} category - Event category
172+
* @returns {Function} Event handler function
173+
*/
174+
function createTrackedEventListener(eventName, category) {
175+
eventCounts[eventName] = 0;
176+
return (event) => {
177+
eventCounts[eventName] += 1;
178+
logEvent(eventName, category, event.detail);
179+
};
180+
}
181+
182+
/**
183+
* Initialize all Universal Editor event listeners
184+
*/
185+
function initUEDebug() {
186+
console.log(
187+
`%c${UE_DEBUG_PREFIX} Initializing Universal Editor debug instrumentation...`,
188+
LOG_STYLES.event,
189+
);
190+
191+
// Register content event listeners
192+
CONTENT_EVENTS.forEach(({ name, description }) => {
193+
document.addEventListener(name, createTrackedEventListener(name, 'content'));
194+
console.log(`%c Listening for: ${name}`, LOG_STYLES.content);
195+
console.log(`%c ${description}`, LOG_STYLES.timestamp);
196+
});
197+
198+
// Register UI event listeners
199+
UI_EVENTS.forEach(({ name, description }) => {
200+
document.addEventListener(name, createTrackedEventListener(name, 'ui'));
201+
console.log(`%c Listening for: ${name}`, LOG_STYLES.ui);
202+
console.log(`%c ${description}`, LOG_STYLES.timestamp);
203+
});
204+
205+
console.log(
206+
`%c${UE_DEBUG_PREFIX} Debug instrumentation ready. Listening for ${CONTENT_EVENTS.length + UI_EVENTS.length} events.`,
207+
LOG_STYLES.event,
208+
);
209+
210+
// Add helper function to window for manual event summary
211+
window.ueDebugSummary = () => {
212+
console.group(`%c${UE_DEBUG_PREFIX} Event Summary`, LOG_STYLES.event);
213+
let totalEvents = 0;
214+
Object.entries(eventCounts).forEach(([event, count]) => {
215+
if (count > 0) {
216+
const style = event.includes('content') ? LOG_STYLES.content : LOG_STYLES.ui;
217+
console.log(`%c${event}: ${count}`, style);
218+
totalEvents += count;
219+
}
220+
});
221+
console.log(`%cTotal events captured: ${totalEvents}`, LOG_STYLES.data);
222+
console.groupEnd();
223+
return eventCounts;
224+
};
225+
226+
// Add helper to clear event counts
227+
window.ueDebugReset = () => {
228+
Object.keys(eventCounts).forEach((key) => {
229+
eventCounts[key] = 0;
230+
});
231+
console.log(`%c${UE_DEBUG_PREFIX} Event counts reset`, LOG_STYLES.event);
232+
};
233+
234+
// Add helper to simulate events for testing
235+
window.ueDebugSimulate = (eventName, detail = {}) => {
236+
const validEvents = [...CONTENT_EVENTS, ...UI_EVENTS].map((e) => e.name);
237+
if (!validEvents.includes(eventName)) {
238+
console.error(
239+
`%c${UE_DEBUG_PREFIX} Invalid event name. Valid events: ${validEvents.join(', ')}`,
240+
LOG_STYLES.error,
241+
);
242+
return;
243+
}
244+
document.dispatchEvent(new CustomEvent(eventName, { detail }));
245+
console.log(`%c${UE_DEBUG_PREFIX} Simulated event: ${eventName}`, LOG_STYLES.event);
246+
};
247+
248+
console.log(
249+
`%c${UE_DEBUG_PREFIX} Helper functions available:`,
250+
LOG_STYLES.event,
251+
);
252+
console.log(' - window.ueDebugSummary() : Show event count summary');
253+
console.log(' - window.ueDebugReset() : Reset event counts');
254+
console.log(' - window.ueDebugSimulate(eventName, detail) : Simulate an event');
255+
}
256+
257+
/**
258+
* Check if page is loaded in Universal Editor context
259+
* @returns {boolean} True if in UE context
260+
*/
261+
function isInUniversalEditor() {
262+
// Check if page is in an iframe (UE loads pages in iframe)
263+
const inIframe = window.self !== window.top;
264+
265+
// Check for UE-specific URL parameters
266+
const urlParams = new URLSearchParams(window.location.search);
267+
const hasUEParams = urlParams.has('wcmmode') || urlParams.has('aue');
268+
269+
// Check for UE-specific meta tags or attributes
270+
const hasUEAttributes = document.querySelector('[data-aue-resource]')
271+
|| document.querySelector('[data-aue-type]');
272+
273+
return inIframe || hasUEParams || hasUEAttributes;
274+
}
275+
276+
/**
277+
* Initialize debug instrumentation
278+
* Only initializes if in Universal Editor context or debug mode is forced
279+
*/
280+
function init() {
281+
const urlParams = new URLSearchParams(window.location.search);
282+
const forceDebug = urlParams.get('ue-debug') === 'true';
283+
284+
if (forceDebug || isInUniversalEditor()) {
285+
initUEDebug();
286+
} else {
287+
console.log(
288+
`%c${UE_DEBUG_PREFIX} Not in Universal Editor context. Add ?ue-debug=true to force enable.`,
289+
LOG_STYLES.timestamp,
290+
);
291+
}
292+
}
293+
294+
// Auto-initialize
295+
init();
296+
297+
export {
298+
initUEDebug,
299+
isInUniversalEditor,
300+
CONTENT_EVENTS,
301+
UI_EVENTS,
302+
};

0 commit comments

Comments
 (0)