Product import
This commit is contained in:
1 parent
7442d10e68
commit
7833e1b668
21 files changed
+763
-185
No files matched your search
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* VITEC – click-to-edit for the "Current value" column of the product text
|
||||
* import (Edit Product view).
|
||||
* EXT:vitec/Resources/Public/Javascript/product-inline-edit.js
|
||||
*
|
||||
* Delegated click handler on [data-vitec-inline-edit] cells (backend CSP
|
||||
* forbids inline handlers). Clicking a cell fetches the FULL raw field value
|
||||
* (the cell itself only shows a truncated preview), swaps in a textarea with
|
||||
* Save/Cancel, and writes through the vitec_product_field_save AJAX route,
|
||||
* which uses the same whitelist and DataHandler path as the form apply.
|
||||
* RTE fields are edited as raw HTML on purpose - no inline WYSIWYG
|
||||
* (decision 2026-08-28).
|
||||
*/
|
||||
import AjaxRequest from "@typo3/core/ajax/ajax-request.js";
|
||||
import Notification from "@typo3/backend/notification.js";
|
||||
|
||||
const SELECTOR = "[data-vitec-inline-edit]";
|
||||
|
||||
function previewOf(cell) {
|
||||
return cell.querySelector("[data-vitec-preview]");
|
||||
}
|
||||
|
||||
function closeEditor(cell) {
|
||||
const editor = cell.querySelector("[data-vitec-editor]");
|
||||
if (editor) {
|
||||
editor.remove();
|
||||
}
|
||||
const preview = previewOf(cell);
|
||||
if (preview) {
|
||||
preview.hidden = false;
|
||||
}
|
||||
delete cell.dataset.vitecEditing;
|
||||
}
|
||||
|
||||
async function openEditor(cell) {
|
||||
if (cell.dataset.vitecEditing === "1") {
|
||||
return;
|
||||
}
|
||||
cell.dataset.vitecEditing = "1";
|
||||
|
||||
const getUrl = TYPO3.settings.ajaxUrls["vitec_product_field_get"];
|
||||
const saveUrl = TYPO3.settings.ajaxUrls["vitec_product_field_save"];
|
||||
if (!getUrl || !saveUrl) {
|
||||
Notification.error("Inline edit", "AJAX routes are not registered.");
|
||||
delete cell.dataset.vitecEditing;
|
||||
return;
|
||||
}
|
||||
|
||||
let value = "";
|
||||
try {
|
||||
const response = await new AjaxRequest(getUrl)
|
||||
.withQueryArguments({ uid: cell.dataset.uid, field: cell.dataset.field })
|
||||
.get();
|
||||
const data = await response.resolve();
|
||||
if (!data.success) {
|
||||
Notification.error("Inline edit", data.message || "Could not load the field value.");
|
||||
delete cell.dataset.vitecEditing;
|
||||
return;
|
||||
}
|
||||
value = data.value;
|
||||
} catch (e) {
|
||||
Notification.error("Inline edit", "Loading the field value failed.");
|
||||
delete cell.dataset.vitecEditing;
|
||||
return;
|
||||
}
|
||||
|
||||
const preview = previewOf(cell);
|
||||
if (preview) {
|
||||
preview.hidden = true;
|
||||
}
|
||||
|
||||
const wrap = document.createElement("div");
|
||||
wrap.setAttribute("data-vitec-editor", "1");
|
||||
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.className = "form-control";
|
||||
textarea.rows = Math.min(14, Math.max(3, Math.ceil(value.length / 80)));
|
||||
textarea.style.fontFamily = "monospace";
|
||||
textarea.style.fontSize = "11px";
|
||||
textarea.value = value;
|
||||
wrap.appendChild(textarea);
|
||||
|
||||
const bar = document.createElement("div");
|
||||
bar.style.marginTop = ".25rem";
|
||||
|
||||
// type="button" is essential: the cells live inside the big mapping <form>,
|
||||
// a bare <button> would submit it.
|
||||
const saveBtn = document.createElement("button");
|
||||
saveBtn.type = "button";
|
||||
saveBtn.className = "btn btn-sm btn-primary";
|
||||
saveBtn.textContent = "Save";
|
||||
|
||||
const cancelBtn = document.createElement("button");
|
||||
cancelBtn.type = "button";
|
||||
cancelBtn.className = "btn btn-sm btn-default";
|
||||
cancelBtn.style.marginLeft = ".5rem";
|
||||
cancelBtn.textContent = "Cancel";
|
||||
|
||||
bar.appendChild(saveBtn);
|
||||
bar.appendChild(cancelBtn);
|
||||
wrap.appendChild(bar);
|
||||
cell.appendChild(wrap);
|
||||
textarea.focus();
|
||||
|
||||
cancelBtn.addEventListener("click", () => closeEditor(cell));
|
||||
textarea.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
closeEditor(cell);
|
||||
}
|
||||
});
|
||||
|
||||
saveBtn.addEventListener("click", async () => {
|
||||
saveBtn.disabled = true;
|
||||
try {
|
||||
const response = await new AjaxRequest(saveUrl).post({
|
||||
uid: cell.dataset.uid,
|
||||
field: cell.dataset.field,
|
||||
value: textarea.value,
|
||||
});
|
||||
const data = await response.resolve();
|
||||
if (!data.success) {
|
||||
Notification.error("Inline edit", data.message || "Saving failed.");
|
||||
saveBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
if (preview) {
|
||||
preview.textContent = data.preview;
|
||||
}
|
||||
closeEditor(cell);
|
||||
Notification.success("Inline edit", cell.dataset.field + " saved.");
|
||||
} catch (e) {
|
||||
Notification.error("Inline edit", "Saving failed.");
|
||||
saveBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
const cell = event.target.closest(SELECTOR);
|
||||
if (cell === null) {
|
||||
return;
|
||||
}
|
||||
// Clicks on the editor's own controls must not re-open it.
|
||||
if (event.target.closest("[data-vitec-editor]")) {
|
||||
return;
|
||||
}
|
||||
openEditor(cell);
|
||||
});
|
||||
Reference in new issue
Block a user