feat(letterhead): introduce custom_css field to move styling out of html fields and to prevent scripts in html fields

This commit is contained in:
Shllokkk 2026-04-23 16:17:50 +05:30
parent 343d55a4a7
commit 0ab6840d1d
2 changed files with 45 additions and 28 deletions

View file

@ -7,29 +7,33 @@
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"letter_head_for",
"letter_head_name",
"module",
"source",
"footer_source",
"column_break_3",
"letter_head_for",
"standard",
"disabled",
"is_default",
"letter_head_image_section",
"align",
"image",
"column_break_dpzk",
"image_height",
"image_width",
"align",
"footer_image_section",
"footer_align",
"footer_image",
"column_break_kfvf",
"footer_image_height",
"footer_image_width",
"header_section",
"content",
"footer_section",
"footer",
"footer_image_section",
"footer_image",
"footer_image_height",
"footer_image_width",
"footer_align",
"style_section",
"custom_css",
"scripts_section",
"header_script",
"footer_script",
@ -47,7 +51,6 @@
"unique": 1
},
{
"depends_on": "letter_head_name",
"fieldname": "source",
"fieldtype": "Select",
"label": "Letter Head Based On",
@ -59,7 +62,6 @@
},
{
"default": "0",
"depends_on": "letter_head_name",
"fieldname": "disabled",
"fieldtype": "Check",
"in_list_view": 1,
@ -69,7 +71,6 @@
},
{
"default": "0",
"depends_on": "letter_head_name",
"fieldname": "is_default",
"fieldtype": "Check",
"in_list_view": 1,
@ -79,25 +80,25 @@
"search_index": 1
},
{
"depends_on": "eval:doc.letter_head_name && doc.source === 'Image'",
"depends_on": "eval:doc.source === 'Image'",
"fieldname": "letter_head_image_section",
"fieldtype": "Section Break",
"label": "Letter Head Image"
},
{
"depends_on": "eval:doc.letter_head_name && doc.source === 'Image'",
"depends_on": "eval: doc.source === 'Image'",
"fieldname": "image",
"fieldtype": "Attach Image",
"label": "Image"
},
{
"depends_on": "eval:doc.source==='HTML' && doc.letter_head_name",
"depends_on": "eval:doc.source==='HTML'",
"fieldname": "header_section",
"fieldtype": "Section Break",
"label": "Header"
},
{
"depends_on": "eval:!doc.__islocal && doc.source==='HTML'",
"depends_on": "eval: doc.source==='HTML'",
"description": "Letter Head in HTML",
"fieldname": "content",
"fieldtype": "HTML Editor",
@ -107,13 +108,13 @@
"oldfieldtype": "Text Editor"
},
{
"depends_on": "eval:doc.footer_source==='HTML' && doc.letter_head_name",
"depends_on": "eval:doc.footer_source==='HTML'",
"fieldname": "footer_section",
"fieldtype": "Section Break",
"label": "Footer"
},
{
"depends_on": "eval:!doc.__islocal",
"depends_on": "eval: doc.footer_source==='HTML'",
"description": "Footer will display correctly only in PDF",
"fieldname": "footer",
"fieldtype": "HTML Editor",
@ -138,7 +139,7 @@
"label": "Image Width (px)"
},
{
"depends_on": "eval:doc.footer_source==='Image' && doc.letter_head_name",
"depends_on": "eval:doc.footer_source==='Image'",
"fieldname": "footer_image_section",
"fieldtype": "Section Break",
"label": "Footer Image"
@ -165,22 +166,20 @@
"options": "Left\nRight\nCenter"
},
{
"default": "HTML",
"depends_on": "letter_head_name",
"fieldname": "footer_source",
"fieldtype": "Select",
"label": "Footer Based On",
"options": "Image\nHTML"
},
{
"depends_on": "eval:!doc.__islocal && doc.source==='HTML'",
"depends_on": "eval: doc.source==='HTML'",
"fieldname": "header_script",
"fieldtype": "Code",
"label": "Header Script",
"options": "Javascript"
},
{
"depends_on": "eval:!doc.__islocal && doc.footer_source==='HTML'",
"depends_on": "eval: doc.footer_source==='HTML'",
"fieldname": "footer_script",
"fieldtype": "Code",
"label": "Footer Script",
@ -189,7 +188,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.header_script || doc.footer_script",
"depends_on": "eval: !doc.__islocal",
"depends_on": "eval: doc.source === 'HTML' || doc.footer_source === 'HTML'",
"fieldname": "scripts_section",
"fieldtype": "Section Break",
"label": "Scripts"
@ -223,6 +222,28 @@
"label": "Module",
"mandatory_depends_on": "eval: doc.standard == \"Yes\"",
"options": "Module Def"
},
{
"fieldname": "column_break_dpzk",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_kfvf",
"fieldtype": "Column Break"
},
{
"depends_on": "eval: doc.source === 'HTML' || doc.footer_source === 'HTML'",
"fieldname": "custom_css",
"fieldtype": "Code",
"label": "Custom CSS",
"options": "CSS"
},
{
"collapsible": 1,
"depends_on": "eval: doc.source === 'HTML' || doc.footer_source === 'HTML'",
"fieldname": "style_section",
"fieldtype": "Section Break",
"label": "Style"
}
],
"icon": "fa fa-font",
@ -230,7 +251,7 @@
"links": [],
"make_attachments_public": 1,
"max_attachments": 3,
"modified": "2026-04-08 13:15:24.935222",
"modified": "2026-04-22 20:25:24.438817",
"modified_by": "Administrator",
"module": "Printing",
"name": "Letter Head",

View file

@ -19,6 +19,7 @@ class LetterHead(Document):
align: DF.Literal["Left", "Right", "Center"]
content: DF.HTMLEditor | None
custom_css: DF.Code | None
disabled: DF.Check
footer: DF.HTMLEditor | None
footer_align: DF.Literal["Left", "Right", "Center"]
@ -39,11 +40,6 @@ class LetterHead(Document):
standard: DF.Literal["No", "Yes"]
# end: auto-generated types
def before_insert(self):
# for better UX, let user set from attachment
if not frappe.flags.in_migrate and not frappe.flags.in_install:
self.source = "Image"
def on_trash(self):
from frappe.defaults import clear_default