fix .json overwriting
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
createJsonTree({
|
||||
container: domElement,
|
||||
data: jsonData,
|
||||
expandInitially = true // optional: expand all nodes
|
||||
onChange: (data) => { }, // optional: callback on change
|
||||
onSave: (data) => { } // optional: if set, a save button will be added
|
||||
});
|
||||
@@ -12,7 +11,7 @@ function createJsonTree({
|
||||
data,
|
||||
onChange = () => {},
|
||||
onSave = null,
|
||||
expandInitially = true
|
||||
readonly = false
|
||||
}) {
|
||||
container.innerHTML = "";
|
||||
container.classList.add("json-tree-root");
|
||||
@@ -22,8 +21,6 @@ function createJsonTree({
|
||||
|
||||
let lastSnapshot = clone(data);
|
||||
|
||||
const expandedPaths = new Set();
|
||||
|
||||
function clone(obj) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
@@ -70,6 +67,7 @@ function createJsonTree({
|
||||
}
|
||||
|
||||
function undo() {
|
||||
if (readonly) return;
|
||||
if (!history.length) return;
|
||||
redoStack.push(clone(data));
|
||||
data = history.pop();
|
||||
@@ -77,6 +75,7 @@ function createJsonTree({
|
||||
}
|
||||
|
||||
function redo() {
|
||||
if (readonly) return;
|
||||
if (!redoStack.length) return;
|
||||
history.push(clone(data));
|
||||
data = redoStack.pop();
|
||||
@@ -84,6 +83,7 @@ function createJsonTree({
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (readonly) return;
|
||||
if (onSave) onSave(data);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ function createJsonTree({
|
||||
}
|
||||
|
||||
function remove(key, parent) {
|
||||
if (readonly) return;
|
||||
if (key === null || parent == null) return;
|
||||
|
||||
if (!confirm("Wirklich löschen?")) return;
|
||||
@@ -109,28 +110,10 @@ function createJsonTree({
|
||||
render();
|
||||
}
|
||||
|
||||
function collectPaths(obj, path = "root") {
|
||||
if (typeof obj !== "object" || obj === null) return;
|
||||
|
||||
expandedPaths.add(path);
|
||||
|
||||
const entries = Array.isArray(obj)
|
||||
? obj.map((v, i) => [i, v])
|
||||
: Object.entries(obj);
|
||||
|
||||
for (const [k, v] of entries) {
|
||||
collectPaths(v, `${path}.${k}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (expandInitially) {
|
||||
collectPaths(data);
|
||||
}
|
||||
|
||||
function render() {
|
||||
container.innerHTML = "";
|
||||
|
||||
if (onSave) {
|
||||
if (onSave && !readonly) {
|
||||
const controls = document.createElement("div");
|
||||
controls.className = "json-controls";
|
||||
|
||||
@@ -174,10 +157,13 @@ function createJsonTree({
|
||||
const removeBtn = document.createElement("span");
|
||||
removeBtn.className = "json-remove";
|
||||
removeBtn.textContent = " [x]";
|
||||
removeBtn.onclick = (evt) => {
|
||||
evt.stopPropagation();
|
||||
remove(key, parent);
|
||||
};
|
||||
|
||||
if (!readonly) {
|
||||
removeBtn.onclick = (evt) => {
|
||||
evt.stopPropagation();
|
||||
remove(key, parent);
|
||||
};
|
||||
}
|
||||
|
||||
// OBJECT / ARRAY
|
||||
if (typeof value === "object" && value !== null) {
|
||||
@@ -201,81 +187,67 @@ function createJsonTree({
|
||||
const children = document.createElement("div");
|
||||
children.className = "json-children";
|
||||
|
||||
const toggleState = () => {
|
||||
if (expandedPaths.has(path)) {
|
||||
expandedPaths.delete(path);
|
||||
children.classList.add("collapsed");
|
||||
} else {
|
||||
expandedPaths.add(path);
|
||||
children.classList.remove("collapsed");
|
||||
}
|
||||
keyLabel.onclick = toggle.onclick = () => {
|
||||
if (readonly) return;
|
||||
children.classList.toggle("collapsed");
|
||||
};
|
||||
|
||||
keyLabel.onclick = toggle.onclick = toggleState;
|
||||
if (!readonly) {
|
||||
addBtn.onclick = () => {
|
||||
let newKey = "";
|
||||
let newValue;
|
||||
|
||||
if (expandedPaths.has(path)) {
|
||||
children.classList.remove("collapsed");
|
||||
} else {
|
||||
children.classList.add("collapsed");
|
||||
feedbox({
|
||||
title: `<span style="color:#f44336">Key</span> hinzufügen`,
|
||||
message: `
|
||||
<div style="display:flex;flex-direction:column;gap:8px;">
|
||||
${!isArray ? `
|
||||
<input id="newJsonKeyName" placeholder="Key Name" style="padding:6px;" />
|
||||
` : ``}
|
||||
<select id="newJsonValueType">
|
||||
<option value="text">Text</option>
|
||||
<option value="number">Zahl</option>
|
||||
<option value="boolean">Boolean</option>
|
||||
<option value="object">Objekt</option>
|
||||
<option value="array">Array</option>
|
||||
</select>
|
||||
</div>
|
||||
`,
|
||||
buttons: {
|
||||
yes: {
|
||||
text: '<b>Anlegen</b>',
|
||||
onClick: () => {
|
||||
pushHistory();
|
||||
|
||||
if (!isArray) {
|
||||
const input = document.querySelector('#newJsonKeyName');
|
||||
newKey = input?.value?.trim();
|
||||
if (!newKey) return;
|
||||
}
|
||||
|
||||
const selectedType = document.querySelector('#newJsonValueType').value;
|
||||
|
||||
switch (selectedType) {
|
||||
case "number": newValue = 0; break;
|
||||
case "boolean": newValue = false; break;
|
||||
case "object": newValue = {}; break;
|
||||
case "array": newValue = []; break;
|
||||
default: newValue = "";
|
||||
}
|
||||
|
||||
if (isArray) value.push(newValue);
|
||||
else value[newKey] = newValue;
|
||||
|
||||
onChange(data);
|
||||
render();
|
||||
}
|
||||
},
|
||||
no: { text: "Abbrechen" }
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
addBtn.onclick = () => {
|
||||
let newKey = "";
|
||||
let newValue;
|
||||
|
||||
feedbox({
|
||||
title: `<span style="color:#f44336">Key</span> hinzufügen`,
|
||||
message: `
|
||||
<div style="display:flex;flex-direction:column;gap:8px;">
|
||||
${!isArray ? `
|
||||
<input id="newJsonKeyName" placeholder="Key Name" style="padding:6px;" />
|
||||
` : ``}
|
||||
<select id="newJsonValueType">
|
||||
<option value="text">Text</option>
|
||||
<option value="number">Zahl</option>
|
||||
<option value="boolean">Boolean</option>
|
||||
<option value="object">Objekt</option>
|
||||
<option value="array">Array</option>
|
||||
</select>
|
||||
</div>
|
||||
`,
|
||||
buttons: {
|
||||
yes: {
|
||||
text: '<b>Anlegen</b>',
|
||||
onClick: () => {
|
||||
pushHistory();
|
||||
|
||||
if (!isArray) {
|
||||
const input = document.querySelector('#newJsonKeyName');
|
||||
newKey = input?.value?.trim();
|
||||
if (!newKey) return;
|
||||
}
|
||||
|
||||
const selectedType = document.querySelector('#newJsonValueType').value;
|
||||
|
||||
switch (selectedType) {
|
||||
case "number": newValue = 0; break;
|
||||
case "boolean": newValue = false; break;
|
||||
case "object": newValue = {}; break;
|
||||
case "array": newValue = []; break;
|
||||
default: newValue = "";
|
||||
}
|
||||
|
||||
if (isArray) {
|
||||
value.push(newValue);
|
||||
} else {
|
||||
value[newKey] = newValue;
|
||||
}
|
||||
|
||||
onChange(data);
|
||||
render();
|
||||
}
|
||||
},
|
||||
no: { text: 'Abbrechen' }
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const inner = document.createElement("div");
|
||||
|
||||
const entries = isArray
|
||||
@@ -292,9 +264,8 @@ function createJsonTree({
|
||||
|
||||
header.appendChild(keyLabel);
|
||||
header.appendChild(toggle);
|
||||
header.appendChild(addBtn);
|
||||
|
||||
if (key !== null) header.appendChild(removeBtn);
|
||||
if (!readonly) header.appendChild(addBtn);
|
||||
if (key !== null && !readonly) header.appendChild(removeBtn);
|
||||
|
||||
wrapper.appendChild(header);
|
||||
wrapper.appendChild(children);
|
||||
@@ -308,18 +279,22 @@ function createJsonTree({
|
||||
input.className = "json-input string";
|
||||
input.value = value;
|
||||
|
||||
input.oninput = () => {
|
||||
pushHistory();
|
||||
parent[key] = input.value;
|
||||
autoResize(input);
|
||||
onChange(data);
|
||||
};
|
||||
if (readonly) {
|
||||
input.disabled = true;
|
||||
} else {
|
||||
input.oninput = () => {
|
||||
pushHistory();
|
||||
parent[key] = input.value;
|
||||
autoResize(input);
|
||||
onChange(data);
|
||||
};
|
||||
}
|
||||
|
||||
setTimeout(() => autoResize(input), 0);
|
||||
|
||||
wrapper.appendChild(keySpan);
|
||||
wrapper.appendChild(input);
|
||||
if (key !== null) wrapper.appendChild(removeBtn);
|
||||
if (key !== null && !readonly) wrapper.appendChild(removeBtn);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -330,18 +305,22 @@ function createJsonTree({
|
||||
input.className = "json-input number";
|
||||
input.value = value;
|
||||
|
||||
input.oninput = () => {
|
||||
pushHistory();
|
||||
parent[key] = Number(input.value);
|
||||
autoResize(input);
|
||||
onChange(data);
|
||||
};
|
||||
if (readonly) {
|
||||
input.disabled = true;
|
||||
} else {
|
||||
input.oninput = () => {
|
||||
pushHistory();
|
||||
parent[key] = Number(input.value);
|
||||
autoResize(input);
|
||||
onChange(data);
|
||||
};
|
||||
}
|
||||
|
||||
setTimeout(() => autoResize(input), 0);
|
||||
|
||||
wrapper.appendChild(keySpan);
|
||||
wrapper.appendChild(input);
|
||||
if (key !== null) wrapper.appendChild(removeBtn);
|
||||
if (key !== null && !readonly) wrapper.appendChild(removeBtn);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -351,15 +330,19 @@ function createJsonTree({
|
||||
input.type = "checkbox";
|
||||
input.checked = value;
|
||||
|
||||
input.onchange = () => {
|
||||
pushHistory();
|
||||
parent[key] = input.checked;
|
||||
onChange(data);
|
||||
};
|
||||
if (readonly) {
|
||||
input.disabled = true;
|
||||
} else {
|
||||
input.onchange = () => {
|
||||
pushHistory();
|
||||
parent[key] = input.checked;
|
||||
onChange(data);
|
||||
};
|
||||
}
|
||||
|
||||
wrapper.appendChild(keySpan);
|
||||
wrapper.appendChild(input);
|
||||
if (key !== null) wrapper.appendChild(removeBtn);
|
||||
if (key !== null && !readonly) wrapper.appendChild(removeBtn);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -368,8 +351,7 @@ function createJsonTree({
|
||||
|
||||
wrapper.appendChild(keySpan);
|
||||
wrapper.appendChild(span);
|
||||
|
||||
if (key !== null) wrapper.appendChild(removeBtn);
|
||||
if (key !== null && !readonly) wrapper.appendChild(removeBtn);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user