Enhance nested loop functionality in Interview Wizard Modal
- Added support for tracking active loop paths, enabling nested loop navigation. - Implemented breadcrumb navigation to display loop hierarchy and allow users to navigate back to parent loops. - Updated rendering logic for nested loops to support fullscreen mode and improved item management with edit, delete, and navigation options. - Enhanced user experience with context headers showing parent loop item details and improved item editing capabilities.
This commit is contained in:
parent
5a171987b2
commit
c3357a784b
|
|
@ -9,6 +9,7 @@ export interface WizardState {
|
||||||
loopContexts: Map<string, unknown[]>; // loop key -> array of collected items (deprecated, use loopRuntimeStates)
|
loopContexts: Map<string, unknown[]>; // loop key -> array of collected items (deprecated, use loopRuntimeStates)
|
||||||
loopRuntimeStates: Map<string, LoopRuntimeState>; // loop step key -> runtime state
|
loopRuntimeStates: Map<string, LoopRuntimeState>; // loop step key -> runtime state
|
||||||
patches: Patch[]; // Collected patches to apply
|
patches: Patch[]; // Collected patches to apply
|
||||||
|
activeLoopPath: string[]; // Stack of loop keys representing current nesting level (e.g. ["items", "item_list"])
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Patch {
|
export interface Patch {
|
||||||
|
|
@ -36,6 +37,7 @@ export function createWizardState(profile: InterviewProfile): WizardState {
|
||||||
loopContexts: new Map(), // Keep for backwards compatibility
|
loopContexts: new Map(), // Keep for backwards compatibility
|
||||||
loopRuntimeStates: new Map(),
|
loopRuntimeStates: new Map(),
|
||||||
patches: [],
|
patches: [],
|
||||||
|
activeLoopPath: [], // Start at top level
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
TextAreaComponent,
|
TextAreaComponent,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import type { InterviewProfile, InterviewStep } from "../interview/types";
|
import type { InterviewProfile, InterviewStep, LoopStep } from "../interview/types";
|
||||||
import {
|
import {
|
||||||
type WizardState,
|
type WizardState,
|
||||||
createWizardState,
|
createWizardState,
|
||||||
|
|
@ -596,6 +596,24 @@ export class InterviewWizardModal extends Modal {
|
||||||
renderLoopStep(step: InterviewStep, containerEl: HTMLElement): void {
|
renderLoopStep(step: InterviewStep, containerEl: HTMLElement): void {
|
||||||
if (step.type !== "loop") return;
|
if (step.type !== "loop") return;
|
||||||
|
|
||||||
|
// Check if we're in a nested loop (fullscreen mode)
|
||||||
|
const currentLoopKey = this.state.activeLoopPath.length > 0
|
||||||
|
? this.state.activeLoopPath[this.state.activeLoopPath.length - 1]
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// If we're in a nested loop, find which nested step it is
|
||||||
|
if (currentLoopKey && currentLoopKey.startsWith(step.key + ".")) {
|
||||||
|
// We're in a nested loop of this step - render it in fullscreen mode
|
||||||
|
this.renderNestedLoopFullscreen(step, containerEl, currentLoopKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, render normal loop (or top-level loop)
|
||||||
|
if (this.state.activeLoopPath.length > 0 && this.state.activeLoopPath[0] !== step.key) {
|
||||||
|
// We're in a different loop's nested loop, don't render this one
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize or get loop runtime state
|
// Initialize or get loop runtime state
|
||||||
let loopState = this.state.loopRuntimeStates.get(step.key);
|
let loopState = this.state.loopRuntimeStates.get(step.key);
|
||||||
if (!loopState) {
|
if (!loopState) {
|
||||||
|
|
@ -619,8 +637,14 @@ export class InterviewWizardModal extends Modal {
|
||||||
nestedStepsCount: step.items.length,
|
nestedStepsCount: step.items.length,
|
||||||
editIndex: loopState.editIndex,
|
editIndex: loopState.editIndex,
|
||||||
commitMode: commitMode,
|
commitMode: commitMode,
|
||||||
|
activeLoopPath: this.state.activeLoopPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Breadcrumb navigation if in nested context
|
||||||
|
if (this.state.activeLoopPath.length > 0) {
|
||||||
|
this.renderBreadcrumb(containerEl, step);
|
||||||
|
}
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
containerEl.createEl("h2", {
|
containerEl.createEl("h2", {
|
||||||
text: step.label || "Loop",
|
text: step.label || "Loop",
|
||||||
|
|
@ -954,6 +978,9 @@ export class InterviewWizardModal extends Modal {
|
||||||
onFieldChange: (fieldId: string, value: unknown) => void
|
onFieldChange: (fieldId: string, value: unknown) => void
|
||||||
): void {
|
): void {
|
||||||
const existingValue = draftValue !== undefined ? String(draftValue) : "";
|
const existingValue = draftValue !== undefined ? String(draftValue) : "";
|
||||||
|
// Use unique key for preview mode tracking in nested loops
|
||||||
|
const previewKey = `${loopKey}.${nestedStep.key}`;
|
||||||
|
const isPreviewMode = this.previewMode.get(previewKey) || false;
|
||||||
|
|
||||||
if (nestedStep.type === "capture_text") {
|
if (nestedStep.type === "capture_text") {
|
||||||
// Field container
|
// Field container
|
||||||
|
|
@ -977,16 +1004,31 @@ export class InterviewWizardModal extends Modal {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Editor container
|
// Container for editor/preview
|
||||||
const editorContainer = fieldContainer.createEl("div", {
|
const editorContainer = fieldContainer.createEl("div", {
|
||||||
cls: "markdown-editor-container",
|
cls: "markdown-editor-container",
|
||||||
});
|
});
|
||||||
editorContainer.style.width = "100%";
|
editorContainer.style.width = "100%";
|
||||||
editorContainer.style.position = "relative";
|
editorContainer.style.position = "relative";
|
||||||
|
|
||||||
|
// Preview container (hidden by default)
|
||||||
|
const previewContainer = editorContainer.createEl("div", {
|
||||||
|
cls: "markdown-preview-container",
|
||||||
|
});
|
||||||
|
previewContainer.style.display = isPreviewMode ? "block" : "none";
|
||||||
|
previewContainer.style.width = "100%";
|
||||||
|
previewContainer.style.minHeight = "240px";
|
||||||
|
previewContainer.style.padding = "1em";
|
||||||
|
previewContainer.style.border = "1px solid var(--background-modifier-border)";
|
||||||
|
previewContainer.style.borderRadius = "4px";
|
||||||
|
previewContainer.style.background = "var(--background-primary)";
|
||||||
|
previewContainer.style.overflowY = "auto";
|
||||||
|
|
||||||
|
// Editor container
|
||||||
const textEditorContainer = editorContainer.createEl("div", {
|
const textEditorContainer = editorContainer.createEl("div", {
|
||||||
cls: "markdown-editor-wrapper",
|
cls: "markdown-editor-wrapper",
|
||||||
});
|
});
|
||||||
|
textEditorContainer.style.display = isPreviewMode ? "none" : "block";
|
||||||
textEditorContainer.style.width = "100%";
|
textEditorContainer.style.width = "100%";
|
||||||
|
|
||||||
const textSetting = new Setting(textEditorContainer);
|
const textSetting = new Setting(textEditorContainer);
|
||||||
|
|
@ -999,10 +1041,18 @@ export class InterviewWizardModal extends Modal {
|
||||||
settingNameEl.style.display = "none";
|
settingNameEl.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let textareaRef: HTMLTextAreaElement | null = null;
|
||||||
|
|
||||||
textSetting.addTextArea((text) => {
|
textSetting.addTextArea((text) => {
|
||||||
|
textareaRef = text.inputEl;
|
||||||
text.setValue(existingValue);
|
text.setValue(existingValue);
|
||||||
text.onChange((value) => {
|
text.onChange((value) => {
|
||||||
onFieldChange(nestedStep.key, value);
|
onFieldChange(nestedStep.key, value);
|
||||||
|
// Update preview if in preview mode
|
||||||
|
const currentPreviewMode = this.previewMode.get(previewKey) || false;
|
||||||
|
if (currentPreviewMode) {
|
||||||
|
this.updatePreview(previewContainer, value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
text.inputEl.rows = 8;
|
text.inputEl.rows = 8;
|
||||||
text.inputEl.style.width = "100%";
|
text.inputEl.style.width = "100%";
|
||||||
|
|
@ -1010,14 +1060,34 @@ export class InterviewWizardModal extends Modal {
|
||||||
text.inputEl.style.boxSizing = "border-box";
|
text.inputEl.style.boxSizing = "border-box";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add toolbar
|
// Add toolbar with preview toggle
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const textarea = textEditorContainer.querySelector("textarea");
|
const textarea = textEditorContainer.querySelector("textarea");
|
||||||
if (textarea) {
|
if (textarea) {
|
||||||
const itemToolbar = createMarkdownToolbar(textarea);
|
const itemToolbar = createMarkdownToolbar(
|
||||||
|
textarea,
|
||||||
|
() => {
|
||||||
|
// Get current value from textarea before toggling
|
||||||
|
const currentValue = textarea.value;
|
||||||
|
// Update draft with current value
|
||||||
|
onFieldChange(nestedStep.key, currentValue);
|
||||||
|
|
||||||
|
// Toggle preview mode
|
||||||
|
const newPreviewMode = !this.previewMode.get(previewKey);
|
||||||
|
this.previewMode.set(previewKey, newPreviewMode);
|
||||||
|
|
||||||
|
// Re-render to show/hide preview
|
||||||
|
this.renderStep();
|
||||||
|
}
|
||||||
|
);
|
||||||
textEditorContainer.insertBefore(itemToolbar, textEditorContainer.firstChild);
|
textEditorContainer.insertBefore(itemToolbar, textEditorContainer.firstChild);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
|
// Render preview if in preview mode
|
||||||
|
if (isPreviewMode && existingValue) {
|
||||||
|
this.updatePreview(previewContainer, existingValue);
|
||||||
|
}
|
||||||
} else if (nestedStep.type === "capture_text_line") {
|
} else if (nestedStep.type === "capture_text_line") {
|
||||||
// Field container
|
// Field container
|
||||||
const fieldContainer = containerEl.createEl("div", {
|
const fieldContainer = containerEl.createEl("div", {
|
||||||
|
|
@ -1112,12 +1182,11 @@ export class InterviewWizardModal extends Modal {
|
||||||
text.inputEl.style.boxSizing = "border-box";
|
text.inputEl.style.boxSizing = "border-box";
|
||||||
});
|
});
|
||||||
} else if (nestedStep.type === "loop") {
|
} else if (nestedStep.type === "loop") {
|
||||||
// Nested loop: render as a nested loop editor
|
// Nested loop: render as a button to enter fullscreen mode
|
||||||
// The draft value should be an array of items
|
|
||||||
const nestedLoopItems = Array.isArray(draftValue) ? draftValue : [];
|
const nestedLoopItems = Array.isArray(draftValue) ? draftValue : [];
|
||||||
|
const nestedLoopKey = `${loopKey}.${nestedStep.key}`;
|
||||||
|
|
||||||
// Get or create nested loop state
|
// Get or create nested loop state
|
||||||
const nestedLoopKey = `${loopKey}.${nestedStep.key}`;
|
|
||||||
let nestedLoopState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
let nestedLoopState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
if (!nestedLoopState) {
|
if (!nestedLoopState) {
|
||||||
nestedLoopState = {
|
nestedLoopState = {
|
||||||
|
|
@ -1129,276 +1198,510 @@ export class InterviewWizardModal extends Modal {
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, nestedLoopState);
|
this.state.loopRuntimeStates.set(nestedLoopKey, nestedLoopState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render nested loop UI - use a simplified 2-pane layout
|
// Field container
|
||||||
const nestedLoopContainer = containerEl.createEl("div", {
|
const fieldContainer = containerEl.createEl("div", {
|
||||||
cls: "nested-loop-container",
|
cls: "mindnet-field",
|
||||||
});
|
});
|
||||||
nestedLoopContainer.style.border = "1px solid var(--background-modifier-border)";
|
|
||||||
nestedLoopContainer.style.borderRadius = "4px";
|
|
||||||
nestedLoopContainer.style.padding = "1em";
|
|
||||||
nestedLoopContainer.style.marginTop = "0.5em";
|
|
||||||
|
|
||||||
|
// Label
|
||||||
if (nestedStep.label) {
|
if (nestedStep.label) {
|
||||||
const labelEl = nestedLoopContainer.createEl("div", {
|
const labelEl = fieldContainer.createEl("div", {
|
||||||
cls: "mindnet-field__label",
|
cls: "mindnet-field__label",
|
||||||
text: nestedStep.label,
|
text: nestedStep.label,
|
||||||
});
|
});
|
||||||
labelEl.style.marginBottom = "0.5em";
|
|
||||||
labelEl.style.fontWeight = "bold";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 2-pane layout for nested loop
|
// Show item count
|
||||||
const nestedPaneContainer = nestedLoopContainer.createEl("div", {
|
const countText = nestedLoopState.items.length > 0
|
||||||
cls: "nested-loop-panes",
|
? `${nestedLoopState.items.length} ${nestedLoopState.items.length === 1 ? "Eintrag" : "Einträge"}`
|
||||||
|
: "Keine Einträge";
|
||||||
|
const countEl = fieldContainer.createEl("div", {
|
||||||
|
cls: "mindnet-field__desc",
|
||||||
|
text: countText,
|
||||||
});
|
});
|
||||||
nestedPaneContainer.style.display = "flex";
|
countEl.style.marginBottom = "0.5em";
|
||||||
nestedPaneContainer.style.gap = "1em";
|
|
||||||
nestedPaneContainer.style.minHeight = "200px";
|
|
||||||
|
|
||||||
// Left pane: Items list (narrower for nested loops)
|
// Button to enter nested loop (fullscreen mode)
|
||||||
const nestedLeftPane = nestedPaneContainer.createEl("div", {
|
const enterBtn = fieldContainer.createEl("button", {
|
||||||
cls: "nested-loop-items-pane",
|
text: nestedLoopState.items.length > 0 ? "Bearbeiten" : "Hinzufügen",
|
||||||
|
cls: "mod-cta",
|
||||||
});
|
});
|
||||||
nestedLeftPane.style.width = "25%";
|
enterBtn.style.width = "100%";
|
||||||
nestedLeftPane.style.borderRight = "1px solid var(--background-modifier-border)";
|
enterBtn.onclick = () => {
|
||||||
nestedLeftPane.style.paddingRight = "1em";
|
// Enter nested loop: add to activeLoopPath
|
||||||
nestedLeftPane.style.maxHeight = "300px";
|
this.state.activeLoopPath.push(nestedLoopKey);
|
||||||
nestedLeftPane.style.overflowY = "auto";
|
this.renderStep();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render breadcrumb navigation showing loop hierarchy.
|
||||||
|
*/
|
||||||
|
private renderBreadcrumb(containerEl: HTMLElement, currentStep: InterviewStep): void {
|
||||||
|
const breadcrumbContainer = containerEl.createEl("div", {
|
||||||
|
cls: "loop-breadcrumb",
|
||||||
|
});
|
||||||
|
breadcrumbContainer.style.display = "flex";
|
||||||
|
breadcrumbContainer.style.alignItems = "center";
|
||||||
|
breadcrumbContainer.style.gap = "0.5em";
|
||||||
|
breadcrumbContainer.style.marginBottom = "1em";
|
||||||
|
breadcrumbContainer.style.padding = "0.5em";
|
||||||
|
breadcrumbContainer.style.background = "var(--background-secondary)";
|
||||||
|
breadcrumbContainer.style.borderRadius = "4px";
|
||||||
|
|
||||||
|
// Build breadcrumb path
|
||||||
|
const path: Array<{ key: string; label: string }> = [];
|
||||||
|
|
||||||
|
// Find all parent loops
|
||||||
|
for (let i = 0; i < this.state.activeLoopPath.length; i++) {
|
||||||
|
const loopKey = this.state.activeLoopPath[i];
|
||||||
|
if (!loopKey) continue;
|
||||||
|
|
||||||
const nestedItemsTitle = nestedLeftPane.createEl("div", {
|
// Extract step key from loop key (e.g., "items.item_list" -> "item_list")
|
||||||
text: "Einträge",
|
const parts = loopKey.split(".");
|
||||||
cls: "mindnet-field__label",
|
const stepKey = parts[parts.length - 1];
|
||||||
|
if (!stepKey) continue;
|
||||||
|
|
||||||
|
// Find the step in the profile
|
||||||
|
const step = this.findStepByKey(stepKey);
|
||||||
|
if (step && step.type === "loop") {
|
||||||
|
path.push({ key: loopKey, label: step.label || stepKey });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render breadcrumb
|
||||||
|
path.forEach((item, index) => {
|
||||||
|
if (index > 0) {
|
||||||
|
breadcrumbContainer.createEl("span", { text: "›" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const breadcrumbItem = breadcrumbContainer.createEl("button", {
|
||||||
|
text: item.label,
|
||||||
|
cls: "breadcrumb-item",
|
||||||
});
|
});
|
||||||
nestedItemsTitle.style.marginBottom = "0.5em";
|
breadcrumbItem.style.background = "transparent";
|
||||||
|
breadcrumbItem.style.border = "none";
|
||||||
|
breadcrumbItem.style.cursor = "pointer";
|
||||||
|
breadcrumbItem.style.textDecoration = index < path.length - 1 ? "underline" : "none";
|
||||||
|
|
||||||
// Render items list
|
if (index < path.length - 1) {
|
||||||
nestedLoopState.items.forEach((item, i) => {
|
breadcrumbItem.onclick = () => {
|
||||||
const itemEl = nestedLeftPane.createEl("div", {
|
// Navigate to this level
|
||||||
cls: "nested-loop-item",
|
this.state.activeLoopPath = this.state.activeLoopPath.slice(0, index + 1);
|
||||||
});
|
this.renderStep();
|
||||||
itemEl.style.padding = "0.5em";
|
};
|
||||||
itemEl.style.marginBottom = "0.25em";
|
}
|
||||||
itemEl.style.background = "var(--background-secondary)";
|
});
|
||||||
itemEl.style.borderRadius = "4px";
|
|
||||||
itemEl.style.cursor = "pointer";
|
// Back button to parent level
|
||||||
|
if (this.state.activeLoopPath.length > 0) {
|
||||||
// Extract first non-empty field value for display
|
const backBtn = breadcrumbContainer.createEl("button", {
|
||||||
let itemText = `Item ${i + 1}`;
|
text: "← Zurück",
|
||||||
if (typeof item === "object" && item !== null) {
|
cls: "mod-cta",
|
||||||
const itemObj = item as Record<string, unknown>;
|
});
|
||||||
// Try to find first non-empty string value
|
backBtn.style.marginLeft = "auto";
|
||||||
for (const [key, value] of Object.entries(itemObj)) {
|
backBtn.onclick = () => {
|
||||||
if (value && typeof value === "string" && value.trim() !== "") {
|
this.state.activeLoopPath.pop();
|
||||||
itemText = value.trim();
|
this.renderStep();
|
||||||
break;
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (item) {
|
|
||||||
itemText = String(item);
|
/**
|
||||||
|
* Find a step by its key in the profile (recursive search).
|
||||||
|
*/
|
||||||
|
private findStepByKey(key: string): InterviewStep | null {
|
||||||
|
const searchInSteps = (steps: InterviewStep[]): InterviewStep | null => {
|
||||||
|
for (const step of steps) {
|
||||||
|
if (step.key === key) {
|
||||||
|
return step;
|
||||||
}
|
}
|
||||||
itemEl.textContent = itemText.length > 40 ? itemText.substring(0, 40) + "..." : itemText;
|
if (step.type === "loop") {
|
||||||
|
const found = searchInSteps(step.items);
|
||||||
// Edit button
|
if (found) return found;
|
||||||
const editBtn = itemEl.createEl("button", {
|
}
|
||||||
text: "✏️",
|
}
|
||||||
cls: "nested-edit-btn",
|
return null;
|
||||||
});
|
};
|
||||||
editBtn.style.float = "right";
|
|
||||||
editBtn.style.marginLeft = "0.5em";
|
return searchInSteps(this.state.profile.steps);
|
||||||
editBtn.onclick = (e) => {
|
}
|
||||||
e.stopPropagation();
|
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
/**
|
||||||
if (currentNestedState) {
|
* Render a nested loop in fullscreen mode (uses full width).
|
||||||
let newState = startEdit(currentNestedState, i);
|
*/
|
||||||
newState = resetItemWizard(newState);
|
private renderNestedLoopFullscreen(
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
parentStep: InterviewStep,
|
||||||
this.renderStep();
|
containerEl: HTMLElement,
|
||||||
}
|
nestedLoopKey: string
|
||||||
};
|
): void {
|
||||||
|
// Extract the nested step from parent step
|
||||||
// Move Up button
|
const nestedStepKey = nestedLoopKey.split(".").pop();
|
||||||
const moveUpBtn = itemEl.createEl("button", {
|
if (!nestedStepKey) return;
|
||||||
text: "↑",
|
|
||||||
cls: "nested-move-up-btn",
|
// parentStep must be a LoopStep to have items
|
||||||
});
|
if (parentStep.type !== "loop") return;
|
||||||
moveUpBtn.style.float = "right";
|
|
||||||
moveUpBtn.style.marginLeft = "0.25em";
|
const loopStep = parentStep as LoopStep;
|
||||||
moveUpBtn.disabled = i === 0;
|
const nestedStep = loopStep.items.find((s: InterviewStep) => s.key === nestedStepKey);
|
||||||
moveUpBtn.onclick = (e) => {
|
if (!nestedStep || nestedStep.type !== "loop") return;
|
||||||
e.stopPropagation();
|
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
// Get nested loop state
|
||||||
if (currentNestedState) {
|
let nestedLoopState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
const newState = moveItemUp(currentNestedState, i);
|
if (!nestedLoopState) {
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
nestedLoopState = {
|
||||||
// Update parent draft
|
items: [],
|
||||||
onFieldChange(nestedStep.key, newState.items);
|
draft: {},
|
||||||
this.renderStep();
|
editIndex: null,
|
||||||
}
|
activeItemStepIndex: 0,
|
||||||
};
|
};
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, nestedLoopState);
|
||||||
// Move Down button
|
}
|
||||||
const moveDownBtn = itemEl.createEl("button", {
|
|
||||||
text: "↓",
|
// Breadcrumb
|
||||||
cls: "nested-move-down-btn",
|
this.renderBreadcrumb(containerEl, nestedStep);
|
||||||
});
|
|
||||||
moveDownBtn.style.float = "right";
|
// Context header: Show parent loop item context
|
||||||
moveDownBtn.style.marginLeft = "0.25em";
|
const contextHeader = containerEl.createEl("div", {
|
||||||
moveDownBtn.disabled = i >= nestedLoopState.items.length - 1;
|
cls: "nested-loop-context",
|
||||||
moveDownBtn.onclick = (e) => {
|
});
|
||||||
e.stopPropagation();
|
contextHeader.style.padding = "1em";
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
contextHeader.style.background = "var(--background-secondary)";
|
||||||
if (currentNestedState) {
|
contextHeader.style.borderRadius = "6px";
|
||||||
const newState = moveItemDown(currentNestedState, i);
|
contextHeader.style.marginBottom = "1.5em";
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
contextHeader.style.border = "1px solid var(--background-modifier-border)";
|
||||||
// Update parent draft
|
|
||||||
onFieldChange(nestedStep.key, newState.items);
|
// Find parent loop context
|
||||||
this.renderStep();
|
const lastDotIndex = nestedLoopKey.lastIndexOf(".");
|
||||||
}
|
if (lastDotIndex > 0) {
|
||||||
};
|
const parentLoopKey = nestedLoopKey.substring(0, lastDotIndex);
|
||||||
|
const parentLoopState = this.state.loopRuntimeStates.get(parentLoopKey);
|
||||||
// Delete button
|
|
||||||
const deleteBtn = itemEl.createEl("button", {
|
|
||||||
text: "🗑️",
|
|
||||||
cls: "nested-delete-btn",
|
|
||||||
});
|
|
||||||
deleteBtn.style.float = "right";
|
|
||||||
deleteBtn.style.marginLeft = "0.25em";
|
|
||||||
deleteBtn.onclick = (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
|
||||||
if (currentNestedState) {
|
|
||||||
const newState = deleteItem(currentNestedState, i);
|
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
|
||||||
// Update parent draft
|
|
||||||
onFieldChange(nestedStep.key, newState.items);
|
|
||||||
this.renderStep();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Right pane: Editor for nested loop (wider for nested loops)
|
if (parentLoopState) {
|
||||||
const nestedRightPane = nestedPaneContainer.createEl("div", {
|
// Find the top-level loop step
|
||||||
cls: "nested-loop-editor-pane",
|
const topLevelLoopKey = nestedLoopKey.split(".")[0];
|
||||||
});
|
if (!topLevelLoopKey) {
|
||||||
nestedRightPane.style.width = "75%";
|
// Fallback if no top-level key found
|
||||||
nestedRightPane.style.flex = "1";
|
const contextTitle = contextHeader.createEl("div", {
|
||||||
|
cls: "context-title",
|
||||||
const nestedEditorTitle = nestedRightPane.createEl("div", {
|
text: "📍 Kontext: " + (parentStep.label || "Parent Loop"),
|
||||||
cls: "mindnet-field__label",
|
});
|
||||||
});
|
contextTitle.style.fontWeight = "bold";
|
||||||
const nestedTitleText = nestedLoopState.editIndex !== null
|
contextTitle.style.marginBottom = "0.5em";
|
||||||
? `Eintrag ${nestedLoopState.editIndex + 1} bearbeiten`
|
contextTitle.style.fontSize = "0.9em";
|
||||||
: "Neuer Eintrag";
|
contextTitle.style.color = "var(--text-muted)";
|
||||||
const nestedStepCounter = nestedStep.items.length > 0
|
} else {
|
||||||
? ` - Schritt ${nestedLoopState.activeItemStepIndex + 1}/${nestedStep.items.length}`
|
const topLevelLoopState = this.state.loopRuntimeStates.get(topLevelLoopKey);
|
||||||
: "";
|
const topLevelStep = this.findStepByKey(topLevelLoopKey);
|
||||||
nestedEditorTitle.textContent = nestedTitleText + nestedStepCounter;
|
|
||||||
nestedEditorTitle.style.marginBottom = "0.5em";
|
// Build context path: top-level loop > nested loop (current)
|
||||||
|
const contextPath: string[] = [];
|
||||||
// Render active nested step
|
if (topLevelStep && topLevelStep.type === "loop") {
|
||||||
if (nestedStep.items.length > 0) {
|
contextPath.push(topLevelStep.label || topLevelLoopKey);
|
||||||
const activeNestedStepIndex = Math.min(nestedLoopState.activeItemStepIndex, nestedStep.items.length - 1);
|
}
|
||||||
const activeNestedNestedStep = nestedStep.items[activeNestedStepIndex];
|
// Add the nested loop label (the one we're currently in)
|
||||||
|
if (nestedStep && nestedStep.type === "loop") {
|
||||||
|
contextPath.push(nestedStep.label || nestedStepKey || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextTitle = contextHeader.createEl("div", {
|
||||||
|
cls: "context-title",
|
||||||
|
});
|
||||||
|
contextTitle.style.fontWeight = "bold";
|
||||||
|
contextTitle.style.marginBottom = "0.5em";
|
||||||
|
contextTitle.style.fontSize = "0.9em";
|
||||||
|
contextTitle.style.color = "var(--text-muted)";
|
||||||
|
|
||||||
|
if (contextPath.length > 0) {
|
||||||
|
contextTitle.textContent = "📍 Kontext: " + contextPath.join(" › ");
|
||||||
|
} else {
|
||||||
|
contextTitle.textContent = "📍 Kontext: " + (parentStep.label || "Parent Loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Recursively render nested step (supports arbitrary nesting depth)
|
// Show which parent item we're editing
|
||||||
if (activeNestedNestedStep) {
|
if (parentLoopState.editIndex !== null) {
|
||||||
const nestedDraftValue = nestedLoopState.draft[activeNestedNestedStep.key];
|
const parentItem = parentLoopState.items[parentLoopState.editIndex];
|
||||||
this.renderLoopNestedStep(
|
if (parentItem && typeof parentItem === "object") {
|
||||||
activeNestedNestedStep,
|
const parentItemObj = parentItem as Record<string, unknown>;
|
||||||
nestedRightPane,
|
const contextInfo = contextHeader.createEl("div", {
|
||||||
nestedLoopKey,
|
cls: "context-info",
|
||||||
nestedDraftValue,
|
});
|
||||||
(fieldId, value) => {
|
contextInfo.style.fontSize = "0.85em";
|
||||||
// Update state without re-rendering to preserve focus
|
contextInfo.style.color = "var(--text-normal)";
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
|
||||||
if (currentNestedState) {
|
// Show parent item fields (excluding the nested loop field itself)
|
||||||
const newState = setDraftField(currentNestedState, fieldId, value);
|
const parentFields: string[] = [];
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
for (const [key, value] of Object.entries(parentItemObj)) {
|
||||||
// Update parent draft without re-rendering
|
if (nestedStepKey && key !== nestedStepKey && value && typeof value === "string" && value.trim() !== "") {
|
||||||
const parentLoopState = this.state.loopRuntimeStates.get(loopKey);
|
const step = loopStep.items.find(s => s.key === key);
|
||||||
if (parentLoopState) {
|
const label = step?.label || key;
|
||||||
const updatedParentDraft = {
|
parentFields.push(`${label}: ${value.trim().substring(0, 60)}${value.trim().length > 60 ? "..." : ""}`);
|
||||||
...parentLoopState.draft,
|
|
||||||
[nestedStep.key]: newState.items,
|
|
||||||
};
|
|
||||||
const updatedParentState = setDraftField(parentLoopState, nestedStep.key, newState.items);
|
|
||||||
this.state.loopRuntimeStates.set(loopKey, updatedParentState);
|
|
||||||
}
|
|
||||||
// Do NOT call renderStep() here - it causes focus loss
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
if (parentFields.length > 0) {
|
||||||
|
contextInfo.textContent = `Item ${parentLoopState.editIndex + 1} - ${parentFields.join(" | ")}`;
|
||||||
|
} else {
|
||||||
|
contextInfo.textContent = `Item ${parentLoopState.editIndex + 1} (bearbeiten)`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const contextInfo = contextHeader.createEl("div", {
|
||||||
|
cls: "context-info",
|
||||||
|
text: `Item ${parentLoopState.editIndex + 1} (bearbeiten)`,
|
||||||
|
});
|
||||||
|
contextInfo.style.fontSize = "0.85em";
|
||||||
|
contextInfo.style.color = "var(--text-normal)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// New item in parent loop
|
||||||
|
const contextInfo = contextHeader.createEl("div", {
|
||||||
|
cls: "context-info",
|
||||||
|
text: "Neues Item (wird erstellt)",
|
||||||
|
});
|
||||||
|
contextInfo.style.fontSize = "0.85em";
|
||||||
|
contextInfo.style.color = "var(--text-muted)";
|
||||||
|
contextInfo.style.fontStyle = "italic";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Navigation buttons for nested loop
|
}
|
||||||
const nestedNav = nestedRightPane.createEl("div", {
|
|
||||||
cls: "nested-loop-navigation",
|
// Title
|
||||||
|
containerEl.createEl("h2", {
|
||||||
|
text: nestedStep.label || "Verschachtelter Loop",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show editing indicator
|
||||||
|
if (nestedLoopState.editIndex !== null) {
|
||||||
|
const indicator = containerEl.createEl("div", {
|
||||||
|
cls: "loop-editing-indicator",
|
||||||
|
text: `✏️ Editing item ${nestedLoopState.editIndex + 1}`,
|
||||||
|
});
|
||||||
|
indicator.style.padding = "0.5em";
|
||||||
|
indicator.style.background = "var(--background-modifier-border-hover)";
|
||||||
|
indicator.style.borderRadius = "4px";
|
||||||
|
indicator.style.marginBottom = "1em";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full-width 2-pane container
|
||||||
|
const paneContainer = containerEl.createEl("div", {
|
||||||
|
cls: "loop-pane-container",
|
||||||
|
});
|
||||||
|
paneContainer.style.display = "flex";
|
||||||
|
paneContainer.style.gap = "1em";
|
||||||
|
paneContainer.style.width = "100%";
|
||||||
|
|
||||||
|
// Left pane: Items list (30% for fullscreen mode)
|
||||||
|
const leftPane = paneContainer.createEl("div", {
|
||||||
|
cls: "loop-items-pane",
|
||||||
|
});
|
||||||
|
leftPane.style.width = "30%";
|
||||||
|
leftPane.style.borderRight = "1px solid var(--background-modifier-border)";
|
||||||
|
leftPane.style.paddingRight = "1em";
|
||||||
|
leftPane.style.maxHeight = "70vh";
|
||||||
|
leftPane.style.overflowY = "auto";
|
||||||
|
|
||||||
|
const itemsTitle = leftPane.createEl("h3", {
|
||||||
|
text: "Einträge",
|
||||||
|
});
|
||||||
|
itemsTitle.style.marginBottom = "0.5em";
|
||||||
|
|
||||||
|
// Render items list (same as normal loop)
|
||||||
|
nestedLoopState.items.forEach((item, i) => {
|
||||||
|
const itemEl = leftPane.createEl("div", {
|
||||||
|
cls: "loop-item",
|
||||||
|
});
|
||||||
|
itemEl.style.padding = "0.75em";
|
||||||
|
itemEl.style.marginBottom = "0.5em";
|
||||||
|
itemEl.style.background = "var(--background-secondary)";
|
||||||
|
itemEl.style.borderRadius = "4px";
|
||||||
|
itemEl.style.cursor = "pointer";
|
||||||
|
|
||||||
|
// Extract first non-empty field value for display
|
||||||
|
let itemText = `Item ${i + 1}`;
|
||||||
|
if (typeof item === "object" && item !== null) {
|
||||||
|
const itemObj = item as Record<string, unknown>;
|
||||||
|
for (const [key, value] of Object.entries(itemObj)) {
|
||||||
|
if (value && typeof value === "string" && value.trim() !== "") {
|
||||||
|
itemText = value.trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item) {
|
||||||
|
itemText = String(item);
|
||||||
|
}
|
||||||
|
itemEl.textContent = itemText.length > 50 ? itemText.substring(0, 50) + "..." : itemText;
|
||||||
|
|
||||||
|
// Action buttons (same as normal loop)
|
||||||
|
const buttonContainer = itemEl.createEl("div", {
|
||||||
|
cls: "loop-item-actions",
|
||||||
|
});
|
||||||
|
buttonContainer.style.display = "flex";
|
||||||
|
buttonContainer.style.gap = "0.25em";
|
||||||
|
buttonContainer.style.marginTop = "0.5em";
|
||||||
|
buttonContainer.style.justifyContent = "flex-end";
|
||||||
|
|
||||||
|
const editBtn = buttonContainer.createEl("button", { text: "✏️ Edit" });
|
||||||
|
editBtn.onclick = () => {
|
||||||
|
let newState = startEdit(nestedLoopState!, i);
|
||||||
|
newState = resetItemWizard(newState);
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
|
this.renderStep();
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveUpBtn = buttonContainer.createEl("button", { text: "↑" });
|
||||||
|
moveUpBtn.disabled = i === 0;
|
||||||
|
moveUpBtn.onclick = () => {
|
||||||
|
const newState = moveItemUp(nestedLoopState!, i);
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
|
this.renderStep();
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveDownBtn = buttonContainer.createEl("button", { text: "↓" });
|
||||||
|
moveDownBtn.disabled = i >= nestedLoopState.items.length - 1;
|
||||||
|
moveDownBtn.onclick = () => {
|
||||||
|
const newState = moveItemDown(nestedLoopState!, i);
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
|
this.renderStep();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteBtn = buttonContainer.createEl("button", { text: "🗑️" });
|
||||||
|
deleteBtn.onclick = () => {
|
||||||
|
const newState = deleteItem(nestedLoopState!, i);
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
|
this.renderStep();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Right pane: Editor (70% for fullscreen mode)
|
||||||
|
const rightPane = paneContainer.createEl("div", {
|
||||||
|
cls: "loop-editor-pane",
|
||||||
|
});
|
||||||
|
rightPane.style.width = "70%";
|
||||||
|
rightPane.style.flex = "1";
|
||||||
|
|
||||||
|
// Subwizard header
|
||||||
|
const itemTitle = rightPane.createEl("h3");
|
||||||
|
const itemTitleText = nestedLoopState.editIndex !== null
|
||||||
|
? `Item: ${nestedLoopState.editIndex + 1} (editing)`
|
||||||
|
: "Item: New";
|
||||||
|
const stepCounter = nestedStep.items.length > 0
|
||||||
|
? ` - Step ${nestedLoopState.activeItemStepIndex + 1}/${nestedStep.items.length}`
|
||||||
|
: "";
|
||||||
|
itemTitle.textContent = itemTitleText + stepCounter;
|
||||||
|
|
||||||
|
// Render active nested step
|
||||||
|
if (nestedStep.items.length > 0) {
|
||||||
|
const activeStepIndex = Math.min(nestedLoopState.activeItemStepIndex, nestedStep.items.length - 1);
|
||||||
|
const activeNestedStep = nestedStep.items[activeStepIndex];
|
||||||
|
|
||||||
|
if (activeNestedStep) {
|
||||||
|
const editorContainer = rightPane.createEl("div", {
|
||||||
|
cls: "loop-item-editor",
|
||||||
});
|
});
|
||||||
nestedNav.style.display = "flex";
|
|
||||||
nestedNav.style.gap = "0.5em";
|
|
||||||
nestedNav.style.marginTop = "1em";
|
|
||||||
nestedNav.style.justifyContent = "space-between";
|
|
||||||
|
|
||||||
// Left: Back/Next
|
const draftValue = nestedLoopState.draft[activeNestedStep.key];
|
||||||
const nestedNavLeft = nestedNav.createEl("div");
|
this.renderLoopNestedStep(
|
||||||
nestedNavLeft.style.display = "flex";
|
activeNestedStep,
|
||||||
nestedNavLeft.style.gap = "0.5em";
|
editorContainer,
|
||||||
|
nestedLoopKey,
|
||||||
|
draftValue,
|
||||||
|
(fieldId, value) => {
|
||||||
|
const currentState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
|
if (currentState) {
|
||||||
|
const newState = setDraftField(currentState, fieldId, value);
|
||||||
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
|
// Update parent draft
|
||||||
|
const lastDotIndex = nestedLoopKey.lastIndexOf(".");
|
||||||
|
if (lastDotIndex > 0) {
|
||||||
|
const parentLoopKey = nestedLoopKey.substring(0, lastDotIndex);
|
||||||
|
if (parentLoopKey) {
|
||||||
|
const parentState = this.state.loopRuntimeStates.get(parentLoopKey);
|
||||||
|
if (parentState && nestedStepKey) {
|
||||||
|
const updatedParentDraft = {
|
||||||
|
...parentState.draft,
|
||||||
|
[nestedStepKey]: newState.items,
|
||||||
|
};
|
||||||
|
const updatedParentState = setDraftField(parentState, nestedStepKey, newState.items);
|
||||||
|
this.state.loopRuntimeStates.set(parentLoopKey, updatedParentState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const nestedBackBtn = nestedNavLeft.createEl("button", {
|
// Navigation buttons (same as normal loop)
|
||||||
text: "← Zurück",
|
const subwizardNav = rightPane.createEl("div", {
|
||||||
|
cls: "loop-subwizard-navigation",
|
||||||
});
|
});
|
||||||
nestedBackBtn.disabled = activeNestedStepIndex === 0;
|
subwizardNav.style.display = "flex";
|
||||||
nestedBackBtn.onclick = () => {
|
subwizardNav.style.gap = "0.5em";
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
subwizardNav.style.marginTop = "1em";
|
||||||
if (currentNestedState) {
|
subwizardNav.style.justifyContent = "space-between";
|
||||||
const newState = itemPrevStep(currentNestedState);
|
|
||||||
|
const itemNavLeft = subwizardNav.createEl("div");
|
||||||
|
itemNavLeft.style.display = "flex";
|
||||||
|
itemNavLeft.style.gap = "0.5em";
|
||||||
|
|
||||||
|
const itemBackBtn = itemNavLeft.createEl("button", { text: "← Item Back" });
|
||||||
|
itemBackBtn.disabled = activeStepIndex === 0;
|
||||||
|
itemBackBtn.onclick = () => {
|
||||||
|
const currentState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
|
if (currentState) {
|
||||||
|
const newState = itemPrevStep(currentState);
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
this.renderStep();
|
this.renderStep();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const nestedNextBtn = nestedNavLeft.createEl("button", {
|
const itemNextBtn = itemNavLeft.createEl("button", { text: "Item Next →" });
|
||||||
text: "Weiter →",
|
itemNextBtn.disabled = activeStepIndex >= nestedStep.items.length - 1;
|
||||||
});
|
itemNextBtn.onclick = () => {
|
||||||
nestedNextBtn.disabled = activeNestedStepIndex >= nestedStep.items.length - 1;
|
const currentState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
nestedNextBtn.onclick = () => {
|
if (currentState) {
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
const newState = itemNextStep(currentState, nestedStep.items.length);
|
||||||
if (currentNestedState) {
|
|
||||||
const newState = itemNextStep(currentNestedState, nestedStep.items.length);
|
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
this.renderStep();
|
this.renderStep();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Right: Save/Clear
|
const itemNavRight = subwizardNav.createEl("div");
|
||||||
const nestedNavRight = nestedNav.createEl("div");
|
itemNavRight.style.display = "flex";
|
||||||
nestedNavRight.style.display = "flex";
|
itemNavRight.style.gap = "0.5em";
|
||||||
nestedNavRight.style.gap = "0.5em";
|
|
||||||
|
|
||||||
const nestedSaveBtn = nestedNavRight.createEl("button", {
|
const doneBtn = itemNavRight.createEl("button", {
|
||||||
text: nestedLoopState.editIndex !== null ? "Speichern" : "Hinzufügen",
|
text: nestedLoopState.editIndex !== null ? "Save Item" : "Done",
|
||||||
cls: "mod-cta",
|
cls: "mod-cta",
|
||||||
});
|
});
|
||||||
nestedSaveBtn.onclick = () => {
|
doneBtn.onclick = () => {
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
const currentState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
if (currentNestedState && isDraftDirty(currentNestedState.draft)) {
|
if (currentState && isDraftDirty(currentState.draft)) {
|
||||||
const newState = commitDraft(currentNestedState);
|
const newState = commitDraft(currentState);
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
// Update parent draft
|
// Update parent draft
|
||||||
onFieldChange(nestedStep.key, newState.items);
|
const lastDotIndex = nestedLoopKey.lastIndexOf(".");
|
||||||
// Re-render to show updated item list
|
if (lastDotIndex > 0 && nestedStepKey) {
|
||||||
|
const parentLoopKey = nestedLoopKey.substring(0, lastDotIndex);
|
||||||
|
if (parentLoopKey) {
|
||||||
|
const parentState = this.state.loopRuntimeStates.get(parentLoopKey);
|
||||||
|
if (parentState) {
|
||||||
|
const updatedParentState = setDraftField(parentState, nestedStepKey, newState.items);
|
||||||
|
this.state.loopRuntimeStates.set(parentLoopKey, updatedParentState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.renderStep();
|
this.renderStep();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (nestedLoopState.editIndex !== null || isDraftDirty(nestedLoopState.draft)) {
|
if (nestedLoopState.editIndex !== null || isDraftDirty(nestedLoopState.draft)) {
|
||||||
const nestedClearBtn = nestedNavRight.createEl("button", {
|
const clearBtn = itemNavRight.createEl("button", { text: "Clear" });
|
||||||
text: "Löschen",
|
clearBtn.onclick = () => {
|
||||||
});
|
const currentState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
||||||
nestedClearBtn.onclick = () => {
|
if (currentState) {
|
||||||
const currentNestedState = this.state.loopRuntimeStates.get(nestedLoopKey);
|
const newState = clearDraft(currentState);
|
||||||
if (currentNestedState) {
|
|
||||||
const newState = clearDraft(currentNestedState);
|
|
||||||
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
this.state.loopRuntimeStates.set(nestedLoopKey, newState);
|
||||||
this.renderStep();
|
this.renderStep();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user