Loading...
Loading...
Compare original and translation side by side
EFAgentPanelef-editEFAgentPanelef-editGUI interaction (canvas drag, inspector change, trim drag, loop toggle)
└─ component.dispatchEvent(createEditCustomEvent(editEvent))
└─ [bubbles: true, composed: true]
└─ EFWorkbench listener → agentPanel.addEdit(event)
└─ Map<editChangeKey, EditEvent> registry (deduplicates)
└─ groupEditsBySelector() → buildAgentPrompt() → copy buttonEFWorkbenchaddEventListener('ef-edit', ...)ef-editGUI交互(画布拖拽、检查器修改、裁剪拖拽、循环切换)
└─ component.dispatchEvent(createEditCustomEvent(editEvent))
└─ [bubbles: true, composed: true]
└─ EFWorkbench 监听器 → agentPanel.addEdit(event)
└─ Map<editChangeKey, EditEvent> 注册表(去重)
└─ groupEditsBySelector() → buildAgentPrompt() → 复制按钮EFWorkbenchaddEventListener('ef-edit', ...)ef-editeditEvents.tseditEvents.ts// EditEvent — what the panel accumulates
interface EditEvent {
operation: EditOperation;
description: string; // human sentence
selector: string; // CSS path from composition root
elementHtml: string; // cleaned outerHTML snippet
timestamp: number;
}
// Operation union — extend here when adding new interaction types
type EditOperation =
| { type: "element-property-changed"; elementId; tagName; label; property; oldValue; newValue }
| { type: "element-moved"; elementId; tagName; label; fromX; fromY; toX; toY }
| { type: "element-resized"; elementId; tagName; label; x; y; width; height }
| { type: "element-rotated"; elementId; tagName; label; rotation }selector::prop:propNameselector::moveselector::resizeselector::rotate// EditEvent — 面板累积的事件类型
interface EditEvent {
operation: EditOperation;
description: string; // 自然语言描述
selector: string; // 从合成根节点出发的CSS路径
elementHtml: string; // 清理后的outerHTML片段
timestamp: number;
}
// 操作类型联合 — 添加新交互类型时在此扩展
type EditOperation =
| { type: "element-property-changed"; elementId; tagName; label; property; oldValue; newValue }
| { type: "element-moved"; elementId; tagName; label; fromX; fromY; toX; toY }
| { type: "element-resized"; elementId; tagName; label; x; y; width; height }
| { type: "element-rotated"; elementId; tagName; label; rotation }selector::prop:propNameselector::moveselector::resizeselector::rotateimport {
createEditCustomEvent, buildSelectorPath, getElementHtml,
buildEditDescription, type ElementPropertyChangedOperation,
} from "../../editEvents.js";
const oldValue = element.someProperty;
element.someProperty = newValue;
const op: ElementPropertyChangedOperation = {
type: "element-property-changed",
elementId: el.id,
tagName: el.tagName.toLowerCase(),
label: el.textContent?.trim().slice(0, 30) || el.id || el.tagName.toLowerCase(),
property: "attr-name", // attribute name as used in HTML source
oldValue,
newValue,
};
this.dispatchEvent(createEditCustomEvent({
operation: op,
description: buildEditDescription(op),
selector: buildSelectorPath(el),
elementHtml: getElementHtml(el),
timestamp: Date.now(),
}));buildPropertyEditEvent(element, property, oldValue, newValue)EFInspector.tsimport {
createEditCustomEvent, buildSelectorPath, getElementHtml,
buildEditDescription, type ElementPropertyChangedOperation,
} from "../../editEvents.js";
const oldValue = element.someProperty;
element.someProperty = newValue;
const op: ElementPropertyChangedOperation = {
type: "element-property-changed",
elementId: el.id,
tagName: el.tagName.toLowerCase(),
label: el.textContent?.trim().slice(0, 30) || el.id || el.tagName.toLowerCase(),
property: "attr-name", // HTML源码中使用的属性名
oldValue,
newValue,
};
this.dispatchEvent(createEditCustomEvent({
operation: op,
description: buildEditDescription(op),
selector: buildSelectorPath(el),
elementHtml: getElementHtml(el),
timestamp: Date.now(),
}));EFInspector.tsbuildPropertyEditEvent(element, property, oldValue, newValue)undefinedundefinedundefinedundefinedef-edithierarchy-reorderEFHierarchyElementReorderedOperationef-editEFHierarchyhierarchy-reorderElementReorderedOperationtrim-change-endcomposed: trueEFTrimHandlesTrackItem.render()@trim-change-endef-trim-handlesEFVideoTrackrender()ef-trim-handlesrender()ef-trim-handles@trim-change@trim-change-endTrackItem.render()render()trim-change-endEFTrimHandlescomposed: trueTrackItem.render()ef-trim-handles@trim-change-endEFVideoTrackrender()ef-trim-handlesrender()ef-trim-handles@trim-change@trim-change-endrender()TrackItem.render()elementPropertySchema.tselementPropertySchema.tsSCHEMA_REGISTRYtimeDescriptor(attr, label, opts)${ms}msenumDescriptor(attr, label, options, condition?)boolDescriptor(attr, label, condition?)numberDescriptor(attr, label, opts)stringDescriptor(attr, label)elementPropertySchema.test.tsSCHEMA_REGISTRYtimeDescriptor(attr, label, opts)${ms}msenumDescriptor(attr, label, options, condition?)boolDescriptor(attr, label, condition?)numberDescriptor(attr, label, opts)stringDescriptor(attr, label)elementPropertySchema.test.tseditEvents.tseditChangeKeyrollUpEditsgroupEditsBySelectorbuildAgentPrompttrim-change-endef-trim-handlesconst trimHandles = track.shadowRoot?.querySelector("ef-trim-handles");
trimHandles?.dispatchEvent(new CustomEvent("trim-change-end", {
detail: { elementId: video.id, type: "start" },
bubbles: true, composed: true,
}));shadowRoot.querySelector("button[title='Loop']").click()documentef-editbubbles: true, composed: truedocumenteditEvents.tseditChangeKeyrollUpEditsgroupEditsBySelectorbuildAgentPromptef-trim-handlestrim-change-endconst trimHandles = track.shadowRoot?.querySelector("ef-trim-handles");
trimHandles?.dispatchEvent(new CustomEvent("trim-change-end", {
detail: { elementId: video.id, type: "start" },
bubbles: true, composed: true,
}));shadowRoot.querySelector("button[title='Loop']").click()documentef-editbubbles: true, composed: truedocument