diff --git a/frappe/custom/doctype/client_script/client_script.js b/frappe/custom/doctype/client_script/client_script.js index 21e7334b82..27d11af4d1 100644 --- a/frappe/custom/doctype/client_script/client_script.js +++ b/frappe/custom/doctype/client_script/client_script.js @@ -8,40 +8,42 @@ frappe.ui.form.on('Client Script', { () => frappe.set_route('List', frm.doc.dt, 'List')); } - frm.add_custom_button(__('Add script for Child Table'), () => { - frappe.model.with_doctype(frm.doc.dt, () => { - const child_tables = frappe.meta.get_docfields(frm.doc.dt, null, { - fieldtype: 'Table' - }).map(df => df.options); + if (frm.doc.view == 'Form') { + frm.add_custom_button(__('Add script for Child Table'), () => { + frappe.model.with_doctype(frm.doc.dt, () => { + const child_tables = frappe.meta.get_docfields(frm.doc.dt, null, { + fieldtype: 'Table' + }).map(df => df.options); - const d = new frappe.ui.Dialog({ - title: __('Select Child Table'), - fields: [ - { - label: __('Select Child Table'), - fieldtype: 'Link', - fieldname: 'cdt', - options: 'DocType', - get_query: () => { - return { - filters: { - istable: 1, - name: ['in', child_tables] - } - }; + const d = new frappe.ui.Dialog({ + title: __('Select Child Table'), + fields: [ + { + label: __('Select Child Table'), + fieldtype: 'Link', + fieldname: 'cdt', + options: 'DocType', + get_query: () => { + return { + filters: { + istable: 1, + name: ['in', child_tables] + } + }; + } } + ], + primary_action: ({ cdt }) => { + cdt = d.get_field('cdt').value; + frm.events.add_script_for_doctype(frm, cdt); + d.hide(); } - ], - primary_action: ({ cdt }) => { - cdt = d.get_field('cdt').value; - frm.events.add_script_for_doctype(frm, cdt); - d.hide(); - } - }); + }); - d.show(); + d.show(); + }); }); - }); + } frm.set_query('dt', { filters: { @@ -51,6 +53,8 @@ frappe.ui.form.on('Client Script', { }, dt(frm) { + frm.toggle_display('view', !frappe.boot.single_types.includes(frm.doc.dt)); + if (!frm.doc.script) { frm.events.add_script_for_doctype(frm, frm.doc.dt); } @@ -61,7 +65,18 @@ frappe.ui.form.on('Client Script', { } }, + view(frm) { + let has_form_boilerplate = frm.doc.script.includes('frappe.ui.form.on') + if (frm.doc.view === 'List' && has_form_boilerplate) { + frm.set_value('script', ''); + } + if (frm.doc.view === 'Form' && !has_form_boilerplate) { + frm.trigger('dt'); + } + }, + add_script_for_doctype(frm, doctype) { + if (!doctype) return; let boilerplate = ` frappe.ui.form.on('${doctype}', { refresh(frm) { diff --git a/frappe/custom/doctype/client_script/client_script.json b/frappe/custom/doctype/client_script/client_script.json index 57e6c68094..db02d8d4bc 100644 --- a/frappe/custom/doctype/client_script/client_script.json +++ b/frappe/custom/doctype/client_script/client_script.json @@ -8,6 +8,7 @@ "engine": "InnoDB", "field_order": [ "dt", + "view", "enabled", "script", "sample" @@ -22,7 +23,8 @@ "oldfieldname": "dt", "oldfieldtype": "Link", "options": "DocType", - "reqd": 1 + "reqd": 1, + "set_only_once": 1 }, { "fieldname": "script", @@ -43,13 +45,21 @@ "fieldname": "enabled", "fieldtype": "Check", "label": "Enabled" + }, + { + "default": "Form", + "fieldname": "view", + "fieldtype": "Select", + "label": "Apply To", + "options": "List\nForm", + "set_only_once": 1 } ], "icon": "fa fa-glass", "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-02-04 13:57:56.509437", + "modified": "2021-03-16 20:33:51.400191", "modified_by": "Administrator", "module": "Custom", "name": "Client Script", diff --git a/frappe/custom/doctype/client_script/client_script.py b/frappe/custom/doctype/client_script/client_script.py index e252e2a750..049f979263 100644 --- a/frappe/custom/doctype/client_script/client_script.py +++ b/frappe/custom/doctype/client_script/client_script.py @@ -3,15 +3,29 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document + class ClientScript(Document): def autoname(self): - self.name = self.dt + self.name = f"{self.dt}-{self.view}" + + def validate(self): + if not self.is_new(): + return + + exists = frappe.db.exists( + "Client Script", {"dt": self.dt, "view": self.view} + ) + if exists: + frappe.throw( + _("Client Script for {0} {1} already exists").format(frappe.bold(self.dt), self.view), + frappe.DuplicateEntryError, + ) def on_update(self): frappe.clear_cache(doctype=self.dt) def on_trash(self): frappe.clear_cache(doctype=self.dt) - diff --git a/frappe/desk/form/meta.py b/frappe/desk/form/meta.py index c63da93a33..e637f4969a 100644 --- a/frappe/desk/form/meta.py +++ b/frappe/desk/form/meta.py @@ -63,7 +63,7 @@ class FormMeta(Meta): "__linked_with", "__messages", "__print_formats", "__workflow_docs", "__form_grid_templates", "__listview_template", "__tree_js", "__dashboard", "__kanban_column_fields", '__templates', - '__custom_js'): + '__custom_js', '__custom_list_js'): d[k] = self.get(k) # d['fields'] = d.get('fields', []) @@ -130,9 +130,23 @@ class FormMeta(Meta): def add_custom_script(self): """embed all require files""" # custom script - custom = frappe.db.get_value("Client Script", {"dt": self.name, "enabled": 1}, "script") or "" + client_scripts = frappe.db.get_all("Client Script", + filters={"dt": self.name, "enabled": 1}, + fields=["script", "view"], + order_by="creation asc" + ) or "" - self.set("__custom_js", custom) + list_script = '' + form_script = '' + for script in client_scripts: + if script.view == 'List': + list_script += script.script + + if script.view == 'Form': + form_script += script.script + + self.set("__custom_js", form_script) + self.set("__custom_list_js", list_script) def add_search_fields(self): """add search fields found in the doctypes indicated by link fields' options""" diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 396cd983fb..6e6635caf6 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -707,25 +707,18 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { const field_html = () => { let html; let _value; - // listview_setting formatter - if ( - this.settings.formatters && - this.settings.formatters[fieldname] - ) { - _value = this.settings.formatters[fieldname](value, df, doc); + let strip_html_required = + df.fieldtype == "Text Editor" || + (df.fetch_from && + ["Text", "Small Text"].includes(df.fieldtype)); + + if (strip_html_required) { + _value = strip_html(value); } else { - let strip_html_required = - df.fieldtype == "Text Editor" || - (df.fetch_from && - ["Text", "Small Text"].includes(df.fieldtype)); - if (strip_html_required) { - _value = strip_html(value); - } else { - _value = - typeof value === "string" - ? frappe.utils.escape_html(value) - : value; - } + _value = + typeof value === "string" + ? frappe.utils.escape_html(value) + : value; } if (df.fieldtype === "Image") { @@ -781,7 +774,15 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { Subject: this.get_subject_html(doc), Field: field_html(), }; - const column_html = html_map[col.type]; + let column_html = html_map[col.type]; + + // listview_setting formatter + if ( + this.settings.formatters && + this.settings.formatters[fieldname] + ) { + column_html = this.settings.formatters[fieldname](value, df, doc); + } return `