95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
|
|
/**
|
|||
|
|
* Task CAD-5 – Block-Editor-Service.
|
|||
|
|
*
|
|||
|
|
* openBlockForEdit legt markierte KOPIEN der Block-Elemente ins
|
|||
|
|
* Dokument (Original unangetastet); saveBlockEdit schreibt die
|
|||
|
|
* bearbeiteten Kopien als neue Blockdefinition zurueck und
|
|||
|
|
* raeumt die Edit-Kopien auf; discardBlockEdit verwirft alles.
|
|||
|
|
* Marker: BLOCK_EDIT_MARKER (properties-Flag + __blockEdit-IDs).
|
|||
|
|
*/
|
|||
|
|
import type { CADElement, BlockDefinition } from '../types/cad.types';
|
|||
|
|
import type { CADDocument } from '../kernel/document/CADDocument';
|
|||
|
|
|
|||
|
|
/** Marker-Flag in properties der Edit-Kopien. */
|
|||
|
|
export const BLOCK_EDIT_MARKER = '__blockEdit';
|
|||
|
|
|
|||
|
|
/** Aktive Edit-Sitzung (Service-State). */
|
|||
|
|
let editSession: { blockId: string; copyIds: string[] } | null = null;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Oeffnet einen Block zur Bearbeitung: Kopien aller Elemente mit
|
|||
|
|
* Edit-Marker werden ins Dokument gelegt (Original bleibt).
|
|||
|
|
* @returns true wenn geoeffnet, false bei unbekannter ID oder
|
|||
|
|
* bereits offener Sitzung.
|
|||
|
|
*/
|
|||
|
|
export function openBlockForEdit(doc: CADDocument, blockId: string): boolean {
|
|||
|
|
if (editSession) return false;
|
|||
|
|
const block = doc.getBlock(blockId);
|
|||
|
|
if (!block) return false;
|
|||
|
|
const copyIds: string[] = [];
|
|||
|
|
doc.transact(() => {
|
|||
|
|
for (const el of block.elements) {
|
|||
|
|
const copy: CADElement = {
|
|||
|
|
...el,
|
|||
|
|
id: `__blockEdit_${blockId}_${copyIds.length}`,
|
|||
|
|
properties: {
|
|||
|
|
...(el.properties as Record<string, unknown>),
|
|||
|
|
[BLOCK_EDIT_MARKER]: true,
|
|||
|
|
},
|
|||
|
|
} as unknown as CADElement;
|
|||
|
|
doc.addElement(copy);
|
|||
|
|
copyIds.push(copy.id);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
editSession = { blockId, copyIds };
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Speichert die Bearbeitung: die markierten Kopien werden als
|
|||
|
|
* neue Elementliste in die Blockdefinition geschrieben (Marker
|
|||
|
|
* entfernt); Edit-Kopien werden aus dem Dokument geloescht.
|
|||
|
|
* @returns blockId der gespeicherten Definition oder null.
|
|||
|
|
*/
|
|||
|
|
export function saveBlockEdit(doc: CADDocument): string | null {
|
|||
|
|
if (!editSession) return null;
|
|||
|
|
const { blockId, copyIds } = editSession;
|
|||
|
|
const elements: CADElement[] = [];
|
|||
|
|
for (const id of copyIds) {
|
|||
|
|
const el = doc.getElement(id);
|
|||
|
|
if (!el) continue;
|
|||
|
|
const { [BLOCK_EDIT_MARKER]: _marker, ...cleanProps } =
|
|||
|
|
el.properties as Record<string, unknown>;
|
|||
|
|
elements.push({ ...el, id: uid('blk'), properties: cleanProps } as unknown as CADElement);
|
|||
|
|
}
|
|||
|
|
const block = doc.getBlock(blockId);
|
|||
|
|
if (block) {
|
|||
|
|
doc.addBlock({ ...block, elements });
|
|||
|
|
}
|
|||
|
|
doc.deleteElements(copyIds);
|
|||
|
|
editSession = null;
|
|||
|
|
return blockId;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Verwirft die Bearbeitung: Edit-Kopien werden geloescht, die
|
|||
|
|
* Blockdefinition bleibt unveraendert.
|
|||
|
|
* @returns true wenn verworfen, false ohne offene Sitzung.
|
|||
|
|
*/
|
|||
|
|
export function discardBlockEdit(doc: CADDocument): boolean {
|
|||
|
|
if (!editSession) return false;
|
|||
|
|
doc.deleteElements(editSession.copyIds);
|
|||
|
|
editSession = null;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** Ist gerade eine Block-Bearbeitung offen? */
|
|||
|
|
export function isBlockEditOpen(): boolean {
|
|||
|
|
return editSession !== null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let uidCounter = 0;
|
|||
|
|
function uid(prefix: string): string {
|
|||
|
|
return `${prefix}_${Date.now().toString(36)}_${uidCounter++}_${Math.random().toString(36).slice(2, 8)}`;
|
|||
|
|
}
|