Product import
This commit is contained in:
@@ -79,7 +79,10 @@
|
||||
</f:for>
|
||||
</select>
|
||||
</td>
|
||||
<td><small>{row.oldPreview}</small></td>
|
||||
<td data-vitec-inline-edit="1" data-uid="{product.uid}" data-field="{row.field}"
|
||||
style="cursor:pointer;" title="Click to edit this field">
|
||||
<small data-vitec-preview="1">{row.oldPreview}</small>
|
||||
</td>
|
||||
<td>
|
||||
<f:if condition="{row.new}">
|
||||
<f:then>
|
||||
@@ -96,6 +99,10 @@
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="apply[]" value="{row.field}"
|
||||
{f:if(condition: row.changed, then: 'checked="checked"')} />
|
||||
<button type="submit" class="btn btn-sm btn-default" style="margin-left:.5rem;"
|
||||
name="applySingle" value="{row.field}"
|
||||
formaction="{f:be.uri(route: 'web_vitecimport.product_apply')}"
|
||||
title="Write only this field now">Save</button>
|
||||
</td>
|
||||
</tr>
|
||||
</f:for>
|
||||
@@ -152,6 +159,10 @@
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="applyRelated[]" value="{rel.index}"
|
||||
{f:if(condition: rel.changed, then: 'checked="checked"')} />
|
||||
<button type="submit" class="btn btn-sm btn-default" style="margin-left:.5rem;"
|
||||
name="applyRelatedSingle" value="{rel.index}"
|
||||
formaction="{f:be.uri(route: 'web_vitecimport.product_apply')}"
|
||||
title="Write only this card now">Save</button>
|
||||
</td>
|
||||
</tr>
|
||||
</f:for>
|
||||
|
||||
@@ -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