/**
* EDI Document Editor
* Allows parsing, visualizing, editing and re-exporting EDI/VDA files
*/
window.EDIBridge = window.EDIBridge || {};
class Editor {
constructor(app) {
this.app = app;
this.initElements();
this.bindEvents();
this.currentDoc = null; // Store { type: 'edifact'|'vda', data: ..., raw: ... }
}
initElements() {
this.dropZone = document.getElementById('editorDropZone');
this.fileInput = document.getElementById('editorFileInput');
this.renderArea = document.getElementById('editorDocumentRender');
this.btnDownload = document.getElementById('btnEditorDownload');
this.btnBack = document.getElementById('btnEditorBack');
this.dropText = document.getElementById('editorDropText');
}
bindEvents() {
if (this.dropZone) {
this.dropZone.onclick = (e) => { e.stopPropagation(); if (this.fileInput) this.fileInput.click(); };
this.dropZone.ondragover = (e) => { e.preventDefault(); this.dropZone.classList.add('dragover'); };
this.dropZone.ondragleave = () => this.dropZone.classList.remove('dragover');
this.dropZone.ondrop = (e) => {
e.preventDefault();
this.dropZone.classList.remove('dragover');
this.handleFile(e.dataTransfer.files[0]);
};
}
if (this.fileInput) {
this.fileInput.onchange = (e) => this.handleFile(e.target.files[0]);
}
}
handleFile(file) {
if (!file) return;
this.fileName = file.name;
const reader = new FileReader();
reader.onload = (e) => {
this.processContent(e.target.result);
};
reader.readAsText(file);
}
processContent(content) {
const trimmed = content.trim();
const upper = trimmed.toUpperCase();
try {
if (upper.startsWith('UNA') || upper.startsWith('UNB')) {
this.parseAndRenderEdifact(trimmed);
} else if (upper.startsWith('711') || upper.startsWith('511')) {
this.parseAndRenderVDA(trimmed);
} else {
alert('Unbekanntes Dateiformat (Weder EDIFACT noch VDA).');
}
} catch (error) {
console.error(error);
alert('Fehler beim Laden/Parsen der Datei im Editor: ' + error.message);
}
}
parseAndRenderEdifact(content) {
const parser = window.EDIBridge.DelforParser;
if (!parser) throw new Error('DelforParser nicht geladen.');
const parsed = parser.parse(content);
this.currentDoc = {
type: 'edifact',
meta: parsed.meta,
segments: parsed.segments,
raw: content
};
this.renderEdifactEditor();
}
parseAndRenderVDA(content) {
const lines = content.split(/\r?\n/).filter(l => l.length >= 3);
const segments = lines.map(l => {
return {
tag: l.substring(0, 3),
rawLine: l,
fields: this.splitVdaLine(l)
};
});
this.currentDoc = {
type: 'vda',
segments: segments,
raw: content
};
this.renderVdaEditor();
}
// A helper to roughly split VDA into fields (since VDA is fixed length, this is a bit arbitrary for editing unless we know exact positions. For generic editing, we can let user deal with the raw string or fixed chunks if we define them. Let's do raw string editing for VDA segments initially to prevent destroying structure, or simple chunking)
splitVdaLine(line) {
// As a simple generic VDA editor, we split it into Tag and the rest of the string
return [
{ label: 'Satzart', value: line.substring(0, 3), readonly: true },
{ label: 'Daten', value: line.substring(3), length: line.length - 3 }
];
}
renderEdifactEditor() {
let html = `
Datei: ${this.fileName} | Typ: EDIFACT | Segmente: ${this.currentDoc.segments.length}
`;
this.currentDoc.segments.forEach((seg, sIdx) => {
html += `
`;
});
html += `
`;
this.showEditor(html);
}
renderVdaEditor() {
let html = `
Datei: ${this.fileName} | Typ: VDA | Sätze: ${this.currentDoc.segments.length}
`;
this.currentDoc.segments.forEach((seg, sIdx) => {
html += `
`;
});
html += `
`;
this.showEditor(html);
}
updateEdifactField(inputElem) {
const sIdx = parseInt(inputElem.getAttribute('data-seg'));
const elIdx = parseInt(inputElem.getAttribute('data-el'));
const subIdx = parseInt(inputElem.getAttribute('data-sub'));
const val = inputElem.value;
if (subIdx === -1) {
this.currentDoc.segments[sIdx].elements[elIdx] = val;
} else {
this.currentDoc.segments[sIdx].elements[elIdx][subIdx] = val;
}
}
updateVdaFieldLength(sIdx, value) {
const lenSpan = document.getElementById(`vda-len-${sIdx}`);
if (lenSpan) {
lenSpan.textContent = value.length + 3; // +3 for tag
// Suggesting length warnings could be added here later
}
}
updateVdaField(inputElem) {
const sIdx = parseInt(inputElem.getAttribute('data-seg'));
const fIdx = parseInt(inputElem.getAttribute('data-field'));
const val = inputElem.value;
this.currentDoc.segments[sIdx].fields[fIdx].value = val;
// Update rawLine
const tag = this.currentDoc.segments[sIdx].fields[0].value;
this.currentDoc.segments[sIdx].rawLine = tag + val;
}
showEditor(html) {
this.renderArea.innerHTML = html;
this.dropZone.style.display = 'none';
this.renderArea.style.display = 'block';
if (this.btnDownload) this.btnDownload.style.display = 'inline-flex';
if (this.btnBack) this.btnBack.style.display = 'inline-flex';
if (window.lucide) {
lucide.createIcons();
}
}
reset() {
this.currentDoc = null;
this.renderArea.innerHTML = '';
this.renderArea.style.display = 'none';
this.dropZone.style.display = 'flex';
if (this.btnDownload) this.btnDownload.style.display = 'none';
if (this.btnBack) this.btnBack.style.display = 'none';
if (this.fileInput) this.fileInput.value = '';
}
downloadDocument() {
if (!this.currentDoc) return;
let output = '';
if (this.currentDoc.type === 'edifact') {
output = this.rebuildEdifact();
} else if (this.currentDoc.type === 'vda') {
output = this.rebuildVda();
}
const blob = new Blob([output], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
let outName = this.fileName;
if (!outName.includes('_edited')) {
const parts = outName.split('.');
if (parts.length > 1) {
const ext = parts.pop();
outName = parts.join('.') + '_edited.' + ext;
} else {
outName += '_edited';
}
}
a.href = url;
a.download = outName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
rebuildEdifact() {
const meta = this.currentDoc.meta;
let out = '';
// Add UNA if it was present
if (this.currentDoc.raw.startsWith('UNA')) {
out += `UNA${meta.subSeparator}${meta.separator}${meta.decimal}${meta.release} ${meta.terminator}`;
}
this.currentDoc.segments.forEach(seg => {
let segStr = seg.tag;
seg.elements.forEach(el => {
segStr += meta.separator;
if (Array.isArray(el)) {
segStr += el.join(meta.subSeparator);
} else {
segStr += el;
}
});
out += segStr + meta.terminator + "\\r\\n";
});
// Very basic rebuilding: standardizing newlines
return out.replace(/\\r\\n/g, '\r\n');
}
rebuildVda() {
return this.currentDoc.segments.map(s => s.rawLine).join('\r\n');
}
escapeHtml(unsafe) {
if (unsafe === undefined || unsafe === null) return '';
return unsafe
.toString()
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
}
window.EDIBridge.Editor = Editor;