diff --git a/frappe/__init__.py b/frappe/__init__.py index 7c62ae1808..8617c528e4 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -372,7 +372,7 @@ def get_module(modulename): return importlib.import_module(modulename) def scrub(txt): - return txt.replace(' ','_').replace('-', '_').replace('/', '_').lower() + return txt.replace(' ','_').replace('-', '_').lower() def unscrub(txt): return txt.replace('_',' ').replace('-', ' ').title() diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 963c7dbb93..24693fe0b5 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -12,6 +12,10 @@ from frappe.model import no_value_fields from frappe.model.document import Document from frappe.model.db_schema import type_map +form_grid_templates = { + "fields": "templates/form_grid/fields.html" +} + class DocType(Document): def validate(self): if not frappe.conf.get("developer_mode"): diff --git a/frappe/modules/__init__.py b/frappe/modules/__init__.py index 9f8890c482..7a301db61f 100644 --- a/frappe/modules/__init__.py +++ b/frappe/modules/__init__.py @@ -44,10 +44,13 @@ def export_doc(doctype, name, module=None): def get_doctype_module(doctype): return frappe.db.get_value('DocType', doctype, 'module') or "core" +doctype_modules = {} def load_doctype_module(doctype, module=None, prefix=""): - if not module: - module = get_doctype_module(doctype) - return frappe.get_module(get_module_name(doctype, module, prefix)) + if not doctype in doctype_modules: + if not module: + module = get_doctype_module(doctype) + doctype_modules[doctype] = frappe.get_module(get_module_name(doctype, module, prefix)) + return doctype_modules[doctype] def get_module_name(doctype, module, prefix=""): from frappe.modules import scrub diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index daefe582ac..163719b174 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -6,6 +6,11 @@ frappe.ui.form.Grid = Class.extend({ $.extend(this, opts); this.fieldinfo = {}; this.doctype = this.df.options; + this.template = null; + if(this.frm.meta.__form_grid_templates + && this.frm.meta.__form_grid_templates[this.df.fieldname]) { + this.template = this.frm.meta.__form_grid_templates[this.df.fieldname]; + } this.is_grid = true; }, make: function() { @@ -61,7 +66,7 @@ frappe.ui.form.Grid = Class.extend({ if(!force && this.data_rows_are_same(data)) { // soft refresh - this.header_row.refresh(); + this.header_row && this.header_row.refresh(); for(var i in this.grid_rows) { this.grid_rows[i].refresh(); } @@ -261,38 +266,27 @@ frappe.ui.form.GridRow = Class.extend({ }, make_static_display: function() { var me = this; - this.make_static_display_template(); this.row.empty(); - $('
' + (this.doc ? this.doc.idx : "#")+ '
') + $('
' + (this.doc ? this.doc.idx : "#")+ '
') .appendTo(this.row); - for(var ci in this.static_display_template) { - var df = this.static_display_template[ci][0]; - var colsize = this.static_display_template[ci][1]; - var txt = this.doc ? - frappe.format(this.doc[df.fieldname], df, null, this.doc) : - __(df.label); - if(this.doc && df.fieldtype === "Select") { - txt = __(txt); - } - var add_class = (["Text", "Small Text"].indexOf(df.fieldtype)===-1) ? - " grid-overflow-ellipsis" : " grid-overflow-no-ellipsis"; - add_class += (["Int", "Currency", "Float"].indexOf(df.fieldtype)!==-1) ? - " text-right": ""; - - $col = $('
') - .html(txt) - .attr("data-fieldname", df.fieldname) - .data("df", df) - .appendTo(this.row) - if(!this.doc) $col.css({"font-weight":"bold"}) + if(this.grid.template) { + $('
').appendTo(this.row) + .html(frappe.render(this.grid.template, {doc:this.doc, frm:this.frm, grid_row: this})); + } else { + this.add_visible_columns(); } - // TODO find a better solution - // append button column + this.add_buttons(); + + $(this.frm.wrapper).trigger("grid-row-render", [this]); + }, + + add_buttons: function() { + var me = this; if(this.doc && this.grid.is_editable()) { if(!this.grid.$row_actions) { - this.grid.$row_actions = $('
\ \ \ @@ -311,8 +305,34 @@ frappe.ui.form.GridRow = Class.extend({ } } - $(this.frm.wrapper).trigger("grid-row-render", [this]); }, + + add_visible_columns: function() { + this.make_static_display_template(); + for(var ci in this.static_display_template) { + var df = this.static_display_template[ci][0]; + var colsize = this.static_display_template[ci][1]; + var txt = this.doc ? + frappe.format(this.doc[df.fieldname], df, null, this.doc) : + __(df.label); + if(this.doc && df.fieldtype === "Select") { + txt = __(txt); + } + var add_class = (["Text", "Small Text"].indexOf(df.fieldtype)===-1) ? + " grid-overflow-ellipsis" : " grid-overflow-no-ellipsis"; + add_class += (["Int", "Currency", "Float"].indexOf(df.fieldtype)!==-1) ? + " text-right": ""; + + $col = $('
') + .html(txt) + .attr("data-fieldname", df.fieldname) + .data("df", df) + .appendTo(this.row) + if(!this.doc) $col.css({"font-weight":"bold"}) + } + + }, + make_static_display_template: function() { if(this.static_display_template) return; @@ -443,55 +463,6 @@ frappe.ui.form.GridRow = Class.extend({ $.extend(me.fields_dict[fieldname], fi); }) - // var me = this, - // make_row = function(label) { - // if(label) - // $('

'+ label +'

\ - //
') - // .appendTo(me.form_area); - // - // var row = $('
') - // .appendTo(me.form_area); - // - // var col_spans = 6; - // if(row.parents(".form-column:first").hasClass("col-md-6")) - // col_spans = 12; - // - // var col1 = $('
').appendTo(row), - // col2 = $('
').appendTo(row); - // - // return [col1, col2]; - // }, - // cols = make_row(), - // cnt = 0; - // - // $.each(me.docfields, function(ci, df) { - // if(!df.hidden) { - // if(df.fieldtype=="Section Break") { - // cols = make_row(df.label); - // cnt = 0; - // return; - // } - // var fieldwrapper = $('
') - // .appendTo(cols[cnt % 2]) - // var fieldobj = make_field(df, me.parent_df.options, - // fieldwrapper.get(0), me.frm); - // fieldobj.docname = me.doc.name; - // fieldobj.refresh(); - // fieldobj.input && - // $(fieldobj.input).css({"max-height": "100px"}); - // - // // set field properties - // // used for setting custom get queries in links - // if(me.grid.fieldinfo[df.fieldname]) - // $.extend(fieldobj, me.grid.fieldinfo[df.fieldname]); - // - // me.fields.push(fieldobj); - // me.fields_dict[df.fieldname] = fieldobj; - // cnt++; - // } - // }); - this.toggle_add_delete_button_display(this.wrapper.find(".panel:first")); this.grid.open_grid_row = this; diff --git a/frappe/public/js/lib/microtemplate.js b/frappe/public/js/lib/microtemplate.js index 361bd3dd8d..3da5dad3ce 100644 --- a/frappe/public/js/lib/microtemplate.js +++ b/frappe/public/js/lib/microtemplate.js @@ -29,6 +29,6 @@ frappe.template.compile = function(str) { return frappe.template.compiled[str]; }; -frappe.render = function(str, data, debug) { +frappe.render = function(str, data) { return frappe.template.compile(str)(data); }; diff --git a/frappe/widgets/form/meta.py b/frappe/widgets/form/meta.py index f36404a5b2..e9d659ecdd 100644 --- a/frappe/widgets/form/meta.py +++ b/frappe/widgets/form/meta.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe, os from frappe.model.meta import Meta -from frappe.modules import scrub, get_module_path +from frappe.modules import scrub, get_module_path, load_doctype_module from frappe.model.workflow import get_workflow_name ###### @@ -35,10 +35,11 @@ class FormMeta(Meta): self.add_code() self.load_print_formats() self.load_workflows() + self.load_form_grid_templates() def as_dict(self, no_nulls=False): d = super(FormMeta, self).as_dict(no_nulls=no_nulls) - for k in ("__js", "__css", "__list_js", "__calendar_js", "__map_js", + for k in ("__js", "__css", "__list_js", "__calendar_js", "__map_js", "__form_grid_templates", "__linked_with", "__messages", "__print_formats", "__workflow_docs"): d[k] = self.get(k) @@ -153,6 +154,18 @@ class FormMeta(Meta): self.set("__workflow_docs", workflow_docs) + def load_form_grid_templates(self): + module = load_doctype_module(self.name) + app = module.__name__.split(".")[0] + print module, app + templates = {} + if hasattr(module, "form_grid_templates"): + for key, path in module.form_grid_templates.iteritems(): + with open(frappe.get_app_path(app, path), "r") as f: + templates[key] = f.read() + + self.set("__form_grid_templates", templates) + def render_jinja(content): if "{% include" in content: content = frappe.get_jenv().from_string(content).render()