frappe.ui.form.on('Production Briefing Form', {
refresh(frm) {
if (!frm._image_editor_button_added) {
frm.fields_dict.briefing_items.grid.add_custom_button(
__('Edit Selected Image'),
() => edit_selected_row_image(frm)
);
frm._image_editor_button_added = true;
}
}
});
/* -------------------------------------------------- */
/* GLOBAL MESSAGE LISTENER (REGISTER ONCE) */
/* -------------------------------------------------- */
if (!window._pbf_image_editor_listener) {
window.addEventListener('message', function (event) {
if (event.origin !== window.location.origin) return;
if (event.data?.type === 'image_edited') {
handleEditedImage(cur_frm, event.data);
}
});
window._pbf_image_editor_listener = true;
}
/* -------------------------------------------------- */
/* EDIT BUTTON HANDLER */
/* -------------------------------------------------- */
function edit_selected_row_image(frm) {
// --------------------------------------------------
// PROJECT RESTRICTION
// --------------------------------------------------
if (frm.doc.project !== "DD-PROJ-2158") {
frappe.msgprint(__('Image editor is allowed only for Project: DD-PROJ-2158'));
return;
}
const grid = frm.fields_dict.briefing_items.grid;
const selected = grid.get_selected_children();
if (!selected.length) {
frappe.msgprint(__('Please select a row.'));
return;
}
if (selected.length > 1) {
frappe.msgprint(__('Please select only one row.'));
return;
}
const row = selected[0];
if (!row.product_design) {
frappe.msgprint(__('No image attached in this row.'));
return;
}
if (!row.item_code) {
frappe.msgprint(__('No Item selected in this row.'));
return;
}
// --------------------------------------------------
// ITEM GROUP CHECK
// --------------------------------------------------
frappe.db.get_value('Item', row.item_code, 'item_group').then(r => {
if (!r.message) return;
if (r.message.item_group !== "Flush Door") {
frappe.msgprint(__('Image editor is allowed only for Item Group: Flush Door'));
return;
}
// All validations passed → Open editor
openImageEditor(row);
});
}
/* -------------------------------------------------- */
/* OPEN IMAGE EDITOR */
/* -------------------------------------------------- */
function openImageEditor(row) {
const file_url = row.attach;
let editor_image_url;
if (file_url.startsWith('/private/')) {
editor_image_url =
`/api/method/frappe.utils.file_manager.download_file` +
`?file_url=${encodeURIComponent(file_url)}`;
} else {
editor_image_url = file_url.startsWith('http')
? file_url
: window.location.origin + file_url;
}
const params = new URLSearchParams({
image_url: editor_image_url,
row_name: row.name
});
window.open(
`/image-editor1?${params.toString()}`,
'pbf',
'width=1400,height=900,resizable=yes,scrollbars=yes'
);
}
/* -------------------------------------------------- */
/* HANDLE EDITED IMAGE */
/* -------------------------------------------------- */
function handleEditedImage(frm, data) {
if (!data.imageData || !data.metadata?.row_name) return;
fetch(data.imageData)
.then(res => res.blob())
.then(blob => {
const file = new File(
[blob],
`edited_${Date.now()}.png`,
{ type: 'image/png' }
);
const formData = new FormData();
formData.append('file', file);
formData.append('is_private', 0);
formData.append('doctype', frm.doctype);
formData.append('docname', frm.docname);
formData.append('fieldname', 'attach');
return fetch('/api/method/upload_file', {
method: 'POST',
body: formData,
headers: {
'X-Frappe-CSRF-Token': frappe.csrf_token
}
});
})
.then(res => res.json())
.then(r => {
if (!r.message?.file_url) return;
const row = frm.doc.briefing_items.find(
d => d.name === data.metadata.row_name
);
if (!row) return;
frappe.model.set_value(
row.doctype,
row.name,
'attach',
r.message.file_url
);
frm.refresh_field('briefing_items');
frappe.show_alert({
message: __('Image updated successfully'),
indicator: 'green'
});
})
.catch(err => {
console.error(err);
frappe.msgprint(__('Failed to save edited image.'));
});
}