Merge pull request #11942 from rmehta/doctype-layout
feat(doctype-layout): Ability to add different layouts to doctypes
This commit is contained in:
commit
a0effc0338
27 changed files with 414 additions and 177 deletions
|
|
@ -209,14 +209,14 @@ Cypress.Commands.add('awesomebar', text => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add('new_form', doctype => {
|
||||
let route = `Form/${doctype}/New ${doctype} 1`;
|
||||
let route = `form/${doctype}/new`;
|
||||
cy.visit(`/app/${route}`);
|
||||
cy.get('body').should('have.attr', 'data-route', route);
|
||||
cy.get('body').should('have.attr', 'data-ajax-state', 'complete');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('go_to_list', doctype => {
|
||||
cy.visit(`/app/List/${doctype}/List`);
|
||||
cy.visit(`/app/list/${doctype}/list`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clear_cache', () => {
|
||||
|
|
|
|||
|
|
@ -24,12 +24,11 @@ frappe.ui.form.on('DocType', {
|
|||
if (!frm.is_new() && !frm.doc.istable) {
|
||||
if (frm.doc.issingle) {
|
||||
frm.add_custom_button(__('Go to {0}', [frm.doc.name]), () => {
|
||||
window.open(`/app/Form/${frm.doc.name}`);
|
||||
// frappe.set_route('Form', frm.doc.name);
|
||||
window.open(`/app/form/${frm.doc.name}`);
|
||||
});
|
||||
} else {
|
||||
frm.add_custom_button(__('Go to {0} List', [frm.doc.name]), () => {
|
||||
window.open(`/app/List/${frm.doc.name}/List`);
|
||||
window.open(`/app/list/${frm.doc.name}/list`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
0
frappe/custom/doctype/doctype_layout/__init__.py
Normal file
0
frappe/custom/doctype/doctype_layout/__init__.py
Normal file
30
frappe/custom/doctype/doctype_layout/doctype_layout.js
Normal file
30
frappe/custom/doctype/doctype_layout/doctype_layout.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2020, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('DocType Layout', {
|
||||
refresh: function(frm) {
|
||||
frm.trigger('document_type');
|
||||
frm.events.set_button(frm);
|
||||
},
|
||||
|
||||
document_type(frm) {
|
||||
frm.set_fields_as_options('fields', frm.doc.document_type, null, [], 'fieldname').then(() => {
|
||||
// child table empty? then show all fields as default
|
||||
if (frm.doc.document_type) {
|
||||
if (!(frm.doc.fields || []).length) {
|
||||
for (let f of frappe.get_doc('DocType', frm.doc.document_type).fields) {
|
||||
frm.add_child('fields', { fieldname: f.fieldname, label: f.label });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
set_button(frm) {
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Go to {0} List', [frm.doc.name]), () => {
|
||||
window.open(`/app/list/${frappe.router.slug(frm.doc.name)}/list`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
60
frappe/custom/doctype/doctype_layout/doctype_layout.json
Normal file
60
frappe/custom/doctype/doctype_layout/doctype_layout.json
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "Prompt",
|
||||
"creation": "2020-11-16 17:05:35.306846",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"document_type",
|
||||
"fields",
|
||||
"client_script"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Document Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "fields",
|
||||
"fieldtype": "Table",
|
||||
"label": "Fields",
|
||||
"options": "DocType Layout Field",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "client_script",
|
||||
"fieldtype": "Code",
|
||||
"label": "Client Script"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-17 15:49:49.669291",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "DocType Layout",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
12
frappe/custom/doctype/doctype_layout/doctype_layout.py
Normal file
12
frappe/custom/doctype/doctype_layout/doctype_layout.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DocTypeLayout(Document):
|
||||
def validate(self):
|
||||
frappe.cache().delete_value('doctype_name_map')
|
||||
10
frappe/custom/doctype/doctype_layout/test_doctype_layout.py
Normal file
10
frappe/custom/doctype/doctype_layout/test_doctype_layout.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestDocTypeLayout(unittest.TestCase):
|
||||
pass
|
||||
0
frappe/custom/doctype/doctype_layout_field/__init__.py
Normal file
0
frappe/custom/doctype/doctype_layout_field/__init__.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2020-11-16 16:03:43.771801",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"label",
|
||||
"fieldname"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "fieldname",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Fieldname",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Label",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-16 17:13:01.892345",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "DocType Layout Field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DocTypeLayoutField(Document):
|
||||
pass
|
||||
|
|
@ -6,11 +6,23 @@ import frappe
|
|||
@frappe.whitelist(allow_guest=True)
|
||||
def get_doctype_name(name):
|
||||
# translates the doctype name from url to name `sales-order` to `Sales Order`
|
||||
# also supports document type layouts
|
||||
# if with_layout is set: return the layout object too
|
||||
|
||||
def get_name_map():
|
||||
name_map = {}
|
||||
for d in frappe.get_all('DocType'):
|
||||
name_map[d.name.lower().replace(' ', '-')] = d.name
|
||||
name_map[d.name.lower().replace(' ', '-')] = frappe._dict(doctype = d.name)
|
||||
|
||||
for d in frappe.get_all('DocType Layout', fields = ['name', 'document_type']):
|
||||
name_map[d.name.lower().replace(' ', '-')] = frappe._dict(doctype = d.document_type, doctype_layout = d.name)
|
||||
|
||||
return name_map
|
||||
|
||||
return frappe.cache().get_value('doctype_name_map', get_name_map).get(name, name)
|
||||
data = frappe._dict(name_map = frappe.cache().get_value('doctype_name_map', get_name_map).get(name, dict(doctype = name)))
|
||||
|
||||
if data.name_map.get('doctype_layout'):
|
||||
# return the layout object
|
||||
frappe.response.docs.append(frappe.get_doc('DocType Layout', data.name_map.get('doctype_layout')).as_dict())
|
||||
|
||||
return data
|
||||
|
|
@ -39,7 +39,6 @@ app_include_js = [
|
|||
app_include_css = [
|
||||
"/assets/css/desk.min.css",
|
||||
"/assets/css/list.min.css",
|
||||
"/assets/css/form.min.css",
|
||||
"/assets/css/report.min.css",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,13 @@ frappe.ui.form.Controller = Class.extend({
|
|||
});
|
||||
|
||||
frappe.ui.form.Form = class FrappeForm {
|
||||
constructor(doctype, parent, in_form) {
|
||||
constructor(doctype, parent, in_form, doctype_layout_name) {
|
||||
this.docname = '';
|
||||
this.doctype = doctype;
|
||||
this.doctype_layout_name = doctype_layout_name;
|
||||
if (doctype_layout_name) {
|
||||
this.doctype_layout = frappe.get_doc('DocType Layout', doctype_layout_name);
|
||||
}
|
||||
this.hidden = false;
|
||||
this.refresh_if_stale_for = 120;
|
||||
|
||||
|
|
@ -30,7 +34,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.custom_buttons = {};
|
||||
this.sections = [];
|
||||
this.grids = [];
|
||||
this.cscript = new frappe.ui.form.Controller({frm:this});
|
||||
this.cscript = new frappe.ui.form.Controller({ frm: this });
|
||||
this.events = {};
|
||||
this.pformat = {};
|
||||
this.fetch_dict = {};
|
||||
|
|
@ -159,6 +163,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.layout = new frappe.ui.form.Layout({
|
||||
parent: this.body,
|
||||
doctype: this.doctype,
|
||||
doctype_layout: this.doctype_layout,
|
||||
frm: this,
|
||||
with_dashboard: true,
|
||||
card_layout: true,
|
||||
|
|
@ -1693,8 +1698,9 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
|
||||
// Filters fields from the reference doctype and sets them as options for a Select field
|
||||
set_fields_as_options(fieldname, reference_doctype, filter_function, default_options=[], table_fieldname) {
|
||||
if (!reference_doctype) return;
|
||||
let options = default_options;
|
||||
if (!reference_doctype) return Promise.resolve();
|
||||
let options = default_options || [];
|
||||
if (!filter_function) filter_function = (f) => f;
|
||||
return new Promise(resolve => {
|
||||
frappe.model.with_doctype(reference_doctype, () => {
|
||||
frappe.get_meta(reference_doctype).fields.map(df => {
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ frappe.form.formatters = {
|
|||
}
|
||||
},
|
||||
Check: function(value) {
|
||||
if(value) {
|
||||
return `<input type="checkbox" class="disabled-selected">`
|
||||
if (value) {
|
||||
return `<input type="checkbox" class="disabled-selected">`;
|
||||
} else {
|
||||
return `<input type="checkbox" class="disabled-deselected">`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,52 +11,73 @@ frappe.ui.form.Layout = Class.extend({
|
|||
$.extend(this, opts);
|
||||
},
|
||||
make: function() {
|
||||
if(!this.parent && this.body) {
|
||||
if (!this.parent && this.body) {
|
||||
this.parent = this.body;
|
||||
}
|
||||
this.wrapper = $('<div class="form-layout">').appendTo(this.parent);
|
||||
this.message = $('<div class="form-message hidden"></div>').appendTo(this.wrapper);
|
||||
if(!this.fields) {
|
||||
if (!this.fields) {
|
||||
this.fields = this.get_doctype_fields();
|
||||
}
|
||||
this.setup_tabbing();
|
||||
this.render();
|
||||
},
|
||||
show_empty_form_message: function() {
|
||||
if(!(this.wrapper.find(".frappe-control:visible").length || this.wrapper.find(".section-head.collapsed").length)) {
|
||||
if (!(this.wrapper.find(".frappe-control:visible").length || this.wrapper.find(".section-head.collapsed").length)) {
|
||||
this.show_message(__("This form does not have any input"));
|
||||
}
|
||||
},
|
||||
|
||||
get_doctype_fields: function() {
|
||||
let fields = [
|
||||
{
|
||||
parent: this.frm.doctype,
|
||||
fieldtype: 'Data',
|
||||
fieldname: '__newname',
|
||||
reqd: 1,
|
||||
hidden: 1,
|
||||
label: __('Name'),
|
||||
get_status: function(field) {
|
||||
if (field.frm && field.frm.is_new()
|
||||
&& field.frm.meta.autoname
|
||||
&& ['prompt', 'name'].includes(field.frm.meta.autoname.toLowerCase())) {
|
||||
return 'Write';
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
}
|
||||
this.get_new_name_field()
|
||||
];
|
||||
fields = fields.concat(frappe.meta.sort_docfields(frappe.meta.docfield_map[this.doctype]));
|
||||
if (this.doctype_layout) {
|
||||
fields = fields.concat(this.get_fields_from_layout())
|
||||
} else {
|
||||
fields = fields.concat(frappe.meta.sort_docfields(frappe.meta.docfield_map[this.doctype]));
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
|
||||
get_new_name_field() {
|
||||
return {
|
||||
parent: this.frm.doctype,
|
||||
fieldtype: 'Data',
|
||||
fieldname: '__newname',
|
||||
reqd: 1,
|
||||
hidden: 1,
|
||||
label: __('Name'),
|
||||
get_status: function(field) {
|
||||
if (field.frm && field.frm.is_new()
|
||||
&& field.frm.meta.autoname
|
||||
&& ['prompt', 'name'].includes(field.frm.meta.autoname.toLowerCase())) {
|
||||
return 'Write';
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
get_fields_from_layout() {
|
||||
const fields = [];
|
||||
for (let f of this.doctype_layout.fields) {
|
||||
const docfield = copy_dict(frappe.meta.docfield_map[this.doctype][f.fieldname]);
|
||||
docfield.label = f.label;
|
||||
fields.push(docfield);
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
|
||||
show_message: function(html, color) {
|
||||
if (this.message_color) {
|
||||
// remove previous color
|
||||
this.message.removeClass(this.message_color);
|
||||
}
|
||||
this.message_color = (color && ['yellow', 'blue'].includes(color)) ? color : 'blue';
|
||||
if(html) {
|
||||
if(html.substr(0, 1)!=='<') {
|
||||
if (html) {
|
||||
if (html.substr(0, 1)!=='<') {
|
||||
// wrap in a block
|
||||
html = '<div>' + html + '</div>';
|
||||
}
|
||||
|
|
@ -139,7 +160,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
const fieldobj = this.init_field(df, render);
|
||||
this.fields_list.push(fieldobj);
|
||||
this.fields_dict[df.fieldname] = fieldobj;
|
||||
if(this.frm) {
|
||||
if (this.frm) {
|
||||
fieldobj.perm = this.frm.perm;
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +193,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
this.fold_btn = head.find(".btn-fold").on("click", function() {
|
||||
var page = $(this).parent().next();
|
||||
if(page.hasClass("hide")) {
|
||||
if (page.hasClass("hide")) {
|
||||
$(this).removeClass("btn-fold").html(__("Hide details"));
|
||||
page.removeClass("hide");
|
||||
frappe.utils.scroll_to($(this), true, 30);
|
||||
|
|
@ -196,7 +217,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
this.section = new frappe.ui.form.Section(this, df);
|
||||
|
||||
// append to layout fields
|
||||
if(df) {
|
||||
if (df) {
|
||||
this.fields_dict[df.fieldname] = this.section;
|
||||
this.fields_list.push(this.section);
|
||||
}
|
||||
|
|
@ -206,14 +227,14 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
make_column: function(df) {
|
||||
this.column = new frappe.ui.form.Column(this.section, df);
|
||||
if(df && df.fieldname) {
|
||||
if (df && df.fieldname) {
|
||||
this.fields_list.push(this.column);
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(doc) {
|
||||
var me = this;
|
||||
if(doc) this.doc = doc;
|
||||
if (doc) this.doc = doc;
|
||||
|
||||
if (this.frm) {
|
||||
this.wrapper.find(".empty-form-alert").remove();
|
||||
|
|
@ -222,7 +243,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
// NOTE this might seem redundant at first, but it needs to be executed when frm.refresh_fields is called
|
||||
me.attach_doc_and_docfields(true);
|
||||
|
||||
if(this.frm && this.frm.wrapper) {
|
||||
if (this.frm && this.frm.wrapper) {
|
||||
$(this.frm.wrapper).trigger("refresh-fields");
|
||||
}
|
||||
|
||||
|
|
@ -256,13 +277,13 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
refresh_fields: function(fields) {
|
||||
let fieldnames = fields.map((field) => {
|
||||
if(field.fieldname) return field.fieldname;
|
||||
if (field.fieldname) return field.fieldname;
|
||||
});
|
||||
|
||||
this.fields_list.map(fieldobj => {
|
||||
if(fieldnames.includes(fieldobj.df.fieldname)) {
|
||||
if (fieldnames.includes(fieldobj.df.fieldname)) {
|
||||
fieldobj.refresh();
|
||||
if(fieldobj.df["default"]) {
|
||||
if (fieldobj.df["default"]) {
|
||||
fieldobj.set_input(fieldobj.df["default"]);
|
||||
}
|
||||
}
|
||||
|
|
@ -275,15 +296,15 @@ frappe.ui.form.Layout = Class.extend({
|
|||
},
|
||||
|
||||
refresh_section_collapse: function() {
|
||||
if(!this.doc) return;
|
||||
if (!this.doc) return;
|
||||
|
||||
for(var i=0; i<this.sections.length; i++) {
|
||||
for (var i=0; i<this.sections.length; i++) {
|
||||
var section = this.sections[i];
|
||||
var df = section.df;
|
||||
if(df && df.collapsible) {
|
||||
if (df && df.collapsible) {
|
||||
var collapse = true;
|
||||
|
||||
if(df.collapsible_depends_on) {
|
||||
if (df.collapsible_depends_on) {
|
||||
collapse = !this.evaluate_depends_on_value(df.collapsible_depends_on);
|
||||
}
|
||||
|
||||
|
|
@ -291,7 +312,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
collapse = false;
|
||||
}
|
||||
|
||||
if(df.fieldname === '_form_dashboard') {
|
||||
if (df.fieldname === '_form_dashboard') {
|
||||
collapse = localStorage.getItem('collapseFormDashboard')==='yes' ? true : false;
|
||||
}
|
||||
|
||||
|
|
@ -302,9 +323,9 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
attach_doc_and_docfields: function(refresh) {
|
||||
var me = this;
|
||||
for(var i=0, l=this.fields_list.length; i<l; i++) {
|
||||
for (var i=0, l=this.fields_list.length; i<l; i++) {
|
||||
var fieldobj = this.fields_list[i];
|
||||
if(me.doc) {
|
||||
if (me.doc) {
|
||||
fieldobj.doc = me.doc;
|
||||
fieldobj.doctype = me.doc.doctype;
|
||||
fieldobj.docname = me.doc.name;
|
||||
|
|
@ -312,7 +333,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
fieldobj.df.fieldname, me.frm ? me.frm.doc.name : me.doc.name) || fieldobj.df;
|
||||
|
||||
// on form change, permissions can change
|
||||
if(me.frm) {
|
||||
if (me.frm) {
|
||||
fieldobj.perm = me.frm.perm;
|
||||
}
|
||||
}
|
||||
|
|
@ -328,11 +349,11 @@ frappe.ui.form.Layout = Class.extend({
|
|||
setup_tabbing: function() {
|
||||
var me = this;
|
||||
this.wrapper.on("keydown", function(ev) {
|
||||
if(ev.which==9) {
|
||||
if (ev.which==9) {
|
||||
var current = $(ev.target),
|
||||
doctype = current.attr("data-doctype"),
|
||||
fieldname = current.attr("data-fieldname");
|
||||
if(doctype)
|
||||
if (doctype)
|
||||
return me.handle_tab(doctype, fieldname, ev.shiftKey);
|
||||
}
|
||||
});
|
||||
|
|
@ -346,25 +367,25 @@ frappe.ui.form.Layout = Class.extend({
|
|||
focused = false;
|
||||
|
||||
// in grid
|
||||
if(doctype != me.doctype) {
|
||||
if (doctype != me.doctype) {
|
||||
grid_row = me.get_open_grid_row();
|
||||
if(!grid_row || !grid_row.layout) {
|
||||
if (!grid_row || !grid_row.layout) {
|
||||
return;
|
||||
}
|
||||
fields = grid_row.layout.fields_list;
|
||||
}
|
||||
|
||||
for(var i=0, len=fields.length; i < len; i++) {
|
||||
if(fields[i].df.fieldname==fieldname) {
|
||||
if(shift) {
|
||||
if(prev) {
|
||||
for (var i=0, len=fields.length; i < len; i++) {
|
||||
if (fields[i].df.fieldname==fieldname) {
|
||||
if (shift) {
|
||||
if (prev) {
|
||||
this.set_focus(prev);
|
||||
} else {
|
||||
$(this.primary_button).focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(i < len-1) {
|
||||
if (i < len-1) {
|
||||
focused = me.focus_on_next_field(i, fields);
|
||||
}
|
||||
|
||||
|
|
@ -372,15 +393,15 @@ frappe.ui.form.Layout = Class.extend({
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(this.is_visible(fields[i]))
|
||||
if (this.is_visible(fields[i]))
|
||||
prev = fields[i];
|
||||
}
|
||||
|
||||
if (!focused) {
|
||||
// last field in this group
|
||||
if(grid_row) {
|
||||
if (grid_row) {
|
||||
// in grid
|
||||
if(grid_row.doc.idx==grid_row.grid.grid_rows.length) {
|
||||
if (grid_row.doc.idx==grid_row.grid.grid_rows.length) {
|
||||
// last row, close it and find next field
|
||||
grid_row.toggle_view(false, function() {
|
||||
grid_row.grid.frm.layout.handle_tab(grid_row.grid.df.parent, grid_row.grid.df.fieldname);
|
||||
|
|
@ -398,12 +419,12 @@ frappe.ui.form.Layout = Class.extend({
|
|||
},
|
||||
focus_on_next_field: function(start_idx, fields) {
|
||||
// loop to find next eligible fields
|
||||
for(var i= start_idx + 1, len = fields.length; i < len; i++) {
|
||||
for (var i= start_idx + 1, len = fields.length; i < len; i++) {
|
||||
var field = fields[i];
|
||||
if(this.is_visible(field)) {
|
||||
if(field.df.fieldtype==="Table") {
|
||||
if (this.is_visible(field)) {
|
||||
if (field.df.fieldtype==="Table") {
|
||||
// open table grid
|
||||
if(!(field.grid.grid_rows && field.grid.grid_rows.length)) {
|
||||
if (!(field.grid.grid_rows && field.grid.grid_rows.length)) {
|
||||
// empty grid, add a new row
|
||||
field.grid.add_new_row();
|
||||
}
|
||||
|
|
@ -411,7 +432,7 @@ frappe.ui.form.Layout = Class.extend({
|
|||
field.grid.grid_rows[0].show_form();
|
||||
return true;
|
||||
|
||||
} else if(!in_list(frappe.model.no_value_type, field.df.fieldtype)) {
|
||||
} else if (!in_list(frappe.model.no_value_type, field.df.fieldtype)) {
|
||||
this.set_focus(field);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -423,15 +444,15 @@ frappe.ui.form.Layout = Class.extend({
|
|||
},
|
||||
set_focus: function(field) {
|
||||
// next is table, show the table
|
||||
if(field.df.fieldtype=="Table") {
|
||||
if(!field.grid.grid_rows.length) {
|
||||
if (field.df.fieldtype=="Table") {
|
||||
if (!field.grid.grid_rows.length) {
|
||||
field.grid.add_new_row(1);
|
||||
} else {
|
||||
field.grid.grid_rows[0].toggle_view(true);
|
||||
}
|
||||
} else if(field.editor) {
|
||||
} else if (field.editor) {
|
||||
field.editor.set_focus();
|
||||
} else if(field.$input) {
|
||||
} else if (field.$input) {
|
||||
field.$input.focus();
|
||||
}
|
||||
},
|
||||
|
|
@ -466,12 +487,12 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
// show / hide
|
||||
if (f.guardian_has_value) {
|
||||
if(f.df.hidden_due_to_dependency) {
|
||||
if (f.df.hidden_due_to_dependency) {
|
||||
f.df.hidden_due_to_dependency = false;
|
||||
f.refresh();
|
||||
}
|
||||
} else {
|
||||
if(!f.df.hidden_due_to_dependency) {
|
||||
if (!f.df.hidden_due_to_dependency) {
|
||||
f.df.hidden_due_to_dependency = true;
|
||||
f.refresh();
|
||||
}
|
||||
|
|
@ -521,27 +542,27 @@ frappe.ui.form.Layout = Class.extend({
|
|||
|
||||
var parent = this.frm ? this.frm.doc : this.doc || null;
|
||||
|
||||
if(typeof(expression) === 'boolean') {
|
||||
if (typeof(expression) === 'boolean') {
|
||||
out = expression;
|
||||
|
||||
} else if(typeof(expression) === 'function') {
|
||||
} else if (typeof(expression) === 'function') {
|
||||
out = expression(doc);
|
||||
|
||||
} else if(expression.substr(0,5)=='eval:') {
|
||||
} else if (expression.substr(0,5)=='eval:') {
|
||||
try {
|
||||
out = eval(expression.substr(5));
|
||||
if(parent && parent.istable && expression.includes('is_submittable')) {
|
||||
if (parent && parent.istable && expression.includes('is_submittable')) {
|
||||
out = true;
|
||||
}
|
||||
} catch(e) {
|
||||
frappe.throw(__('Invalid "depends_on" expression'));
|
||||
}
|
||||
|
||||
} else if(expression.substr(0,3)=='fn:' && this.frm) {
|
||||
} else if (expression.substr(0,3)=='fn:' && this.frm) {
|
||||
out = this.frm.script_manager.trigger(expression.substr(3), this.doctype, this.docname);
|
||||
} else {
|
||||
var value = doc[expression];
|
||||
if($.isArray(value)) {
|
||||
if ($.isArray(value)) {
|
||||
out = !!value.length;
|
||||
} else {
|
||||
out = !!value;
|
||||
|
|
@ -560,7 +581,7 @@ frappe.ui.form.Section = Class.extend({
|
|||
this.fields_dict = {};
|
||||
|
||||
this.make();
|
||||
// if(this.frm)
|
||||
// if (this.frm)
|
||||
// this.section.body.css({"padding":"0px 3%"})
|
||||
this.row = {
|
||||
wrapper: this.wrapper
|
||||
|
|
@ -573,7 +594,7 @@ frappe.ui.form.Section = Class.extend({
|
|||
this.refresh();
|
||||
},
|
||||
make: function() {
|
||||
if(!this.layout.page) {
|
||||
if (!this.layout.page) {
|
||||
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper);
|
||||
}
|
||||
let make_card = this.layout.card_layout && this.df.fieldname !== '_form_dashboard';
|
||||
|
|
@ -581,15 +602,15 @@ frappe.ui.form.Section = Class.extend({
|
|||
.appendTo(this.layout.page);
|
||||
this.layout.sections.push(this);
|
||||
|
||||
if(this.df) {
|
||||
if(this.df.label) {
|
||||
if (this.df) {
|
||||
if (this.df.label) {
|
||||
this.make_head();
|
||||
}
|
||||
if(this.df.description) {
|
||||
if (this.df.description) {
|
||||
$('<div class="col-sm-12 small text-muted form-section-description">' + __(this.df.description) + '</div>')
|
||||
.appendTo(this.wrapper);
|
||||
}
|
||||
if(this.df.cssClass) {
|
||||
if (this.df.cssClass) {
|
||||
this.wrapper.addClass(this.df.cssClass);
|
||||
}
|
||||
if (this.df.hide_border) {
|
||||
|
|
@ -620,14 +641,14 @@ frappe.ui.form.Section = Class.extend({
|
|||
}
|
||||
},
|
||||
refresh: function() {
|
||||
if(!this.df)
|
||||
if (!this.df)
|
||||
return;
|
||||
|
||||
// hide if explictly hidden
|
||||
var hide = this.df.hidden || this.df.hidden_due_to_dependency;
|
||||
|
||||
// hide if no perm
|
||||
if(!hide && this.layout && this.layout.frm && !this.layout.frm.get_perm(this.df.permlevel || 0, "read")) {
|
||||
if (!hide && this.layout && this.layout.frm && !this.layout.frm.get_perm(this.df.permlevel || 0, "read")) {
|
||||
hide = true;
|
||||
}
|
||||
|
||||
|
|
@ -639,7 +660,7 @@ frappe.ui.form.Section = Class.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
if(hide===undefined) {
|
||||
if (hide===undefined) {
|
||||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +704,7 @@ frappe.ui.form.Section = Class.extend({
|
|||
|
||||
frappe.ui.form.Column = Class.extend({
|
||||
init: function(section, df) {
|
||||
if(!df) df = {};
|
||||
if (!df) df = {};
|
||||
|
||||
this.df = df;
|
||||
this.section = section;
|
||||
|
|
|
|||
|
|
@ -156,16 +156,22 @@ frappe.ui.form.ScriptManager = Class.extend({
|
|||
return handlers;
|
||||
},
|
||||
setup: function() {
|
||||
var doctype = this.frm.meta;
|
||||
var me = this;
|
||||
const doctype = this.frm.meta;
|
||||
const me = this;
|
||||
let client_script;
|
||||
|
||||
// js
|
||||
var cs = doctype.__js;
|
||||
if(cs) {
|
||||
var tmp = eval(cs);
|
||||
// process the custom script for this form
|
||||
if (this.frm.doctype_layout) {
|
||||
client_script = this.frm.doctype_layout.client_script;
|
||||
} else {
|
||||
client_script = doctype.__js;
|
||||
}
|
||||
|
||||
if(doctype.__custom_js) {
|
||||
if (client_script) {
|
||||
eval(client_script);
|
||||
}
|
||||
|
||||
if(!this.frm.doctype_layout && doctype.__custom_js) {
|
||||
try {
|
||||
eval(doctype.__custom_js);
|
||||
} catch(e) {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ frappe.ui.form.set_users = function(data, type) {
|
|||
current: users
|
||||
});
|
||||
|
||||
if (cur_frm && cur_frm.doc && cur_frm.doc.doctype===doctype && cur_frm.doc.name==docname) {
|
||||
if (cur_frm && cur_frm.doc && cur_frm.doc.doctype===doctype
|
||||
&& cur_frm.doc.name==docname && cur_frm.viewers) {
|
||||
cur_frm.viewers.refresh(true, type);
|
||||
}
|
||||
};
|
||||
|
|
@ -34,7 +34,7 @@ frappe.views.BaseList = class BaseList {
|
|||
|
||||
setup_defaults() {
|
||||
this.page_name = frappe.get_route_str();
|
||||
this.page_title = this.page_title || __(this.doctype);
|
||||
this.page_title = this.page_title || frappe.router.doctype_layout || __(this.doctype);
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
this.settings = frappe.listview_settings[this.doctype] || {};
|
||||
this.user_settings = frappe.get_user_settings(this.doctype);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
const last_view = user_settings.last_view;
|
||||
frappe.set_route(
|
||||
"list",
|
||||
frappe.router.slug(doctype),
|
||||
frappe.views.is_valid(last_view) ? last_view : "list"
|
||||
frappe.router.doctype_layout || doctype,
|
||||
frappe.views.is_valid(last_view) ? last_view.toLowerCase() : "list"
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -232,7 +232,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
set_primary_action() {
|
||||
if (this.can_create) {
|
||||
this.page.set_primary_action(
|
||||
`${__("Add")} ${__(this.doctype)}`,
|
||||
`${__("Add")} ${frappe.router.doctype_layout || __(this.doctype)}`,
|
||||
() => {
|
||||
if (this.settings.primary_action) {
|
||||
this.settings.primary_action();
|
||||
|
|
@ -871,7 +871,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
? encodeURIComponent(doc.name)
|
||||
: doc.name;
|
||||
|
||||
return "/app/form/" + frappe.router.slug(this.doctype) + "/" + docname;
|
||||
return "/app/form/" + frappe.router.slug(frappe.router.doctype_layout || this.doctype) + "/" + docname;
|
||||
}
|
||||
|
||||
get_seen_class(doc) {
|
||||
|
|
@ -1402,7 +1402,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
items.push({
|
||||
label: __("Import"),
|
||||
action: () =>
|
||||
frappe.set_route("List", "Data Import", {
|
||||
frappe.set_route("list", "data-import", {
|
||||
reference_doctype: doctype,
|
||||
}),
|
||||
standard: true,
|
||||
|
|
@ -1413,7 +1413,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
items.push({
|
||||
label: __("User Permissions"),
|
||||
action: () =>
|
||||
frappe.set_route("List", "User Permission", {
|
||||
frappe.set_route("list", "user-permission", {
|
||||
allow: doctype,
|
||||
}),
|
||||
standard: true,
|
||||
|
|
@ -1435,9 +1435,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
action: () => {
|
||||
if (!this.meta) return;
|
||||
if (this.meta.custom) {
|
||||
frappe.set_route("Form", "DocType", doctype);
|
||||
frappe.set_route("form", "doctype", doctype);
|
||||
} else if (!this.meta.custom) {
|
||||
frappe.set_route("Form", "Customize Form", {
|
||||
frappe.set_route("form", "customize-form", {
|
||||
doc_type: doctype,
|
||||
});
|
||||
}
|
||||
|
|
@ -1469,7 +1469,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
// edit doctype
|
||||
items.push({
|
||||
label: __("Edit DocType"),
|
||||
action: () => frappe.set_route("Form", "DocType", doctype),
|
||||
action: () => frappe.set_route("form", "doctype", doctype),
|
||||
standard: true,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ frappe.views.Views = class Views {
|
|||
set_current_view() {
|
||||
this.current_view = 'List';
|
||||
const route = frappe.get_route();
|
||||
const view_name = frappe.utils.to_title_case(route[2] || '')
|
||||
const view_name = frappe.utils.to_title_case(route[2] || '');
|
||||
if (route.length > 2 && frappe.views.view_modes.includes(view_name)) {
|
||||
this.current_view = view_name;
|
||||
|
||||
|
|
@ -34,15 +34,21 @@ frappe.views.Views = class Views {
|
|||
}
|
||||
}
|
||||
|
||||
set_route(view, calendar_name) {
|
||||
const route = ['list', frappe.router.doctype_layout || this.doctype, view];
|
||||
if (calendar_name) route.push(calendar_name);
|
||||
frappe.set_route(route);
|
||||
}
|
||||
|
||||
setup_views() {
|
||||
const views = {
|
||||
'List': {
|
||||
condition: true,
|
||||
action: () => frappe.set_route('list', this.doctype, 'list')
|
||||
action: () => this.set_route('list')
|
||||
},
|
||||
'Report': {
|
||||
condition: true,
|
||||
action: () => frappe.set_route('list', this.doctype, 'report'),
|
||||
action: () => this.set_route('report'),
|
||||
current_view_handler: () => {
|
||||
const reports = this.get_reports();
|
||||
this.setup_dropdown_in_sidebar(
|
||||
|
|
@ -50,18 +56,18 @@ frappe.views.Views = class Views {
|
|||
reports,
|
||||
{
|
||||
label: __('Report Builder'),
|
||||
action: () => frappe.set_route('list', this.doctype, 'report')
|
||||
action: () => this.set_route('report')
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
'Dashboard': {
|
||||
condition: true,
|
||||
action: () => frappe.set_route('list', this.doctype, 'dashboard')
|
||||
action: () => this.set_route('dashboard')
|
||||
},
|
||||
'Calendar': {
|
||||
condition: frappe.views.calendar[this.doctype],
|
||||
action: () => frappe.set_route('list', this.doctype, 'calendar', 'default'),
|
||||
action: () => this.set_route('calendar', 'default'),
|
||||
current_view_handler: () => {
|
||||
this.get_calendars().then(calendars => {
|
||||
this.setup_dropdown_in_sidebar(
|
||||
|
|
@ -73,11 +79,11 @@ frappe.views.Views = class Views {
|
|||
},
|
||||
'Gantt': {
|
||||
condition: frappe.views.calendar[this.doctype],
|
||||
action: () => frappe.set_route('list', this.doctype, 'gantt')
|
||||
action: () => this.set_route('gantt')
|
||||
},
|
||||
'Inbox': {
|
||||
condition: this.doctype === "Communication" && frappe.boot.email_accounts.length,
|
||||
action: () => frappe.set_route('list', this.doctype, 'inbox'),
|
||||
action: () => this.set_route('inbox'),
|
||||
current_view_handler: () => {
|
||||
const accounts = this.get_email_accounts();
|
||||
let default_action;
|
||||
|
|
@ -96,11 +102,11 @@ frappe.views.Views = class Views {
|
|||
},
|
||||
'Image': {
|
||||
condition: this.list_view.meta.image_field,
|
||||
action: () => frappe.set_route('list', this.doctype, 'image')
|
||||
action: () => this.set_route('image')
|
||||
},
|
||||
'Tree': {
|
||||
condition: frappe.treeview_settings[this.doctype] || frappe.get_meta(this.doctype).is_tree,
|
||||
action: () => frappe.set_route('list', this.doctype, 'tree')
|
||||
action: () => this.set_route('tree')
|
||||
},
|
||||
'Kanban': {
|
||||
condition: true,
|
||||
|
|
@ -147,7 +153,7 @@ frappe.views.Views = class Views {
|
|||
</div>`;
|
||||
} else {
|
||||
items.map(item => {
|
||||
if (item.name == frappe.get_route().slice(-1)[0]) {
|
||||
if (item.name == frappe.utils.to_title_case(frappe.get_route().slice(-1)[0] || '')) {
|
||||
placeholder = item.name;
|
||||
}
|
||||
html += `<li><a class="dropdown-item" href="#${item.route}">${item.name}</a></li>`;
|
||||
|
|
@ -206,7 +212,7 @@ frappe.views.Views = class Views {
|
|||
const last_opened_kanban = frappe.model.user_settings[this.doctype]['Kanban']
|
||||
&& frappe.model.user_settings[this.doctype]['Kanban'].last_kanban_board;
|
||||
if (last_opened_kanban) {
|
||||
frappe.set_route('List', this.doctype, 'kanban', last_opened_kanban);
|
||||
frappe.set_route('list', this.doctype, 'kanban', last_opened_kanban);
|
||||
} else {
|
||||
frappe.views.KanbanView.show_kanban_dialog(this.doctype, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ $.extend(frappe.model, {
|
|||
if(!cnt[doctype])
|
||||
cnt[doctype] = 0;
|
||||
cnt[doctype]++;
|
||||
return __('New') + ' '+ __(doctype) + ' ' + cnt[doctype];
|
||||
return frappe.router.slug(`new-${doctype}-${cnt[doctype]}`);
|
||||
},
|
||||
|
||||
set_default_values: function(doc, parent_doc) {
|
||||
|
|
@ -170,20 +170,20 @@ $.extend(frappe.model, {
|
|||
|
||||
// 3 - look in default of docfield
|
||||
if (df['default']) {
|
||||
|
||||
if (df["default"] == "__user" || df["default"].toLowerCase() == "user") {
|
||||
const default_val = String(df['default']);
|
||||
if (default_val == "__user" || default_val.toLowerCase() == "user") {
|
||||
return frappe.session.user;
|
||||
|
||||
} else if (df["default"] == "user_fullname") {
|
||||
} else if (default_val == "user_fullname") {
|
||||
return frappe.session.user_fullname;
|
||||
|
||||
} else if (df["default"] == "Today") {
|
||||
} else if (default_val == "Today") {
|
||||
return frappe.datetime.get_today();
|
||||
|
||||
} else if ((df["default"] || "").toLowerCase() === "now") {
|
||||
} else if ((default_val || "").toLowerCase() === "now") {
|
||||
return frappe.datetime.now_datetime();
|
||||
|
||||
} else if (df["default"][0]===":") {
|
||||
} else if (default_val[0]===":") {
|
||||
var boot_doc = frappe.model.get_default_from_boot_docs(df, doc, parent_doc);
|
||||
var is_allowed_boot_doc = !has_user_permissions || allowed_records.includes(boot_doc);
|
||||
|
||||
|
|
|
|||
|
|
@ -273,6 +273,11 @@ $.extend(frappe.model, {
|
|||
return frappe.boot.treeviews.indexOf(doctype) != -1;
|
||||
},
|
||||
|
||||
is_fresh(doc) {
|
||||
// returns true if document has been recently loaded (5 seconds ago)
|
||||
return doc && doc.__last_sync_on && ((new Date() - doc.__last_sync_on)) < 5000;
|
||||
},
|
||||
|
||||
can_import: function(doctype, frm) {
|
||||
// system manager can always import
|
||||
if(frappe.user_roles.includes("System Manager")) return true;
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@ $('body').on('click', 'a', function(e) {
|
|||
if (e.currentTarget.getAttribute('onclick')) return;
|
||||
|
||||
const href = e.currentTarget.getAttribute('href');
|
||||
if (href==='#') return;
|
||||
|
||||
if (href==='#' || href==='') {
|
||||
if (href==='') {
|
||||
return override(e, '/app');
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ frappe.router = {
|
|||
current_route: null,
|
||||
doctype_names: {},
|
||||
factory_views: ['form', 'list', 'report', 'tree', 'print'],
|
||||
layout_mapped: {},
|
||||
|
||||
route() {
|
||||
// resolve the route from the URL or hash
|
||||
|
|
@ -91,16 +93,21 @@ frappe.router = {
|
|||
return new Promise((resolve) => {
|
||||
const route = frappe.router.current_route = frappe.router.parse();
|
||||
const factory = route[0].toLowerCase();
|
||||
const set_name = () => {
|
||||
const d = frappe.router.doctype_names[route[1]];
|
||||
route[1] = d.doctype;
|
||||
frappe.router.doctype_layout = d.doctype_layout;
|
||||
resolve();
|
||||
};
|
||||
|
||||
if (frappe.router.factory_views.includes(factory)) {
|
||||
// translate the doctype to its original name
|
||||
if (frappe.router.doctype_names[route[1]]) {
|
||||
route[1] = frappe.router.doctype_names[route[1]];
|
||||
resolve();
|
||||
set_name();
|
||||
} else {
|
||||
frappe.xcall('frappe.desk.utils.get_doctype_name', {name: route[1]}).then((data) => {
|
||||
route[1] = frappe.router.doctype_names[route[1]] = data;
|
||||
resolve();
|
||||
frappe.router.doctype_names[route[1]] = data.name_map;
|
||||
set_name();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<header class="navbar navbar-expand sticky-top" role="navigation">
|
||||
<div class="container">
|
||||
<a class="navbar-brand navbar-home" href="#">
|
||||
<a class="navbar-brand navbar-home" href="/app">
|
||||
<img class="app-logo" style="width: {{ navbar_settings.logo_width || 24 }}px" src="{{ frappe.app.logo_url }}">
|
||||
</a>
|
||||
<ul class="nav navbar-nav d-none d-sm-flex" id="navbar-breadcrumbs"></ul>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ frappe.breadcrumbs = {
|
|||
}
|
||||
|
||||
let set_list_breadcrumb = (doctype) => {
|
||||
if (doctype==="User"
|
||||
if ((doctype==="User" && !frappe.user.has_role('System Manager'))
|
||||
|| frappe.get_doc('DocType', doctype).issingle) {
|
||||
// no user listview for non-system managers and single doctypes
|
||||
} else {
|
||||
|
|
@ -118,7 +118,7 @@ frappe.breadcrumbs = {
|
|||
let view = frappe.model.user_settings[breadcrumbs.doctype].last_view || 'Tree';
|
||||
route = view + '/' + breadcrumbs.doctype;
|
||||
} else {
|
||||
route = 'List/' + breadcrumbs.doctype;
|
||||
route = 'list/' + (frappe.router.doctype_layout || breadcrumbs.doctype);
|
||||
}
|
||||
$(`<li><a href="/app/${route}">${doctype}</a></li>`)
|
||||
.appendTo($breadcrumbs)
|
||||
|
|
@ -132,8 +132,8 @@ frappe.breadcrumbs = {
|
|||
if (breadcrumbs.doctype && frappe.get_route()[0] === "print") {
|
||||
set_list_breadcrumb(breadcrumbs.doctype);
|
||||
let docname = frappe.get_route()[2];
|
||||
let form_route = `form/${frappe.router.slug(breadcrumbs.doctype)}/${docname}`;
|
||||
$(`<li><a href="#${form_route}">${docname}</a></li>`)
|
||||
let form_route = `/app/form/${frappe.router.slug(breadcrumbs.doctype)}/${docname}`;
|
||||
$(`<li><a href="${form_route}">${docname}</a></li>`)
|
||||
.appendTo($breadcrumbs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,21 +5,25 @@ frappe.provide('frappe.views.formview');
|
|||
|
||||
frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
||||
make(route) {
|
||||
var me = this,
|
||||
dt = route[1];
|
||||
var doctype = route[1],
|
||||
doctype_layout = frappe.router.doctype_layout || doctype;
|
||||
|
||||
if(!frappe.views.formview[dt]) {
|
||||
frappe.model.with_doctype(dt, function() {
|
||||
me.page = frappe.container.add_page("Form/" + dt);
|
||||
frappe.views.formview[dt] = me.page;
|
||||
me.page.frm = new frappe.ui.form.Form(dt, me.page, true);
|
||||
me.show_doc(route);
|
||||
if (!frappe.views.formview[doctype_layout]) {
|
||||
frappe.model.with_doctype(doctype, () => {
|
||||
this.page = frappe.container.add_page("form/" + doctype_layout);
|
||||
frappe.views.formview[doctype_layout] = this.page;
|
||||
this.page.frm = new frappe.ui.form.Form(doctype, this.page, true, frappe.router.doctype_layout);
|
||||
this.show_doc(route);
|
||||
});
|
||||
} else {
|
||||
me.show_doc(route);
|
||||
this.show_doc(route);
|
||||
}
|
||||
|
||||
if(!this.initialized) {
|
||||
this.setup_events();
|
||||
}
|
||||
|
||||
setup_events() {
|
||||
if (!this.initialized) {
|
||||
$(document).on("page-change", function() {
|
||||
frappe.ui.form.close_grid_form();
|
||||
});
|
||||
|
|
@ -34,47 +38,57 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
|
|||
frappe.ui.form.set_users(data, 'typers');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
show_doc(route) {
|
||||
var dt = route[1],
|
||||
dn = route.slice(2).join("/"),
|
||||
me = this;
|
||||
var doctype = route[1],
|
||||
doctype_layout = frappe.router.doctype_layout || doctype,
|
||||
name = route.slice(2).join("/");
|
||||
|
||||
if(frappe.model.new_names[dn]) {
|
||||
dn = frappe.model.new_names[dn];
|
||||
frappe.set_route("Form", dt, dn);
|
||||
if (frappe.model.new_names[name]) {
|
||||
// document has been renamed, reroute
|
||||
name = frappe.model.new_names[name];
|
||||
frappe.set_route("Form", doctype_layout, name);
|
||||
return;
|
||||
}
|
||||
|
||||
frappe.model.with_doc(dt, dn, function(dn, r) {
|
||||
if(r && r['403']) return; // not permitted
|
||||
const doc = frappe.get_doc(doctype, name);
|
||||
if (doc && (doc.__islocal || frappe.model.is_recent(doc))) {
|
||||
// is document available and recent?
|
||||
this.render(doctype_layout, name);
|
||||
} else {
|
||||
this.fetch_and_render(doctype, name, doctype_layout);
|
||||
}
|
||||
}
|
||||
|
||||
if(!(locals[dt] && locals[dt][dn])) {
|
||||
// doc not found, but starts with New,
|
||||
// make a new doc and set it
|
||||
var new_str = __("New") + " ";
|
||||
if(dn && dn.substr(0, new_str.length)==new_str) {
|
||||
var new_name = frappe.model.make_new_doc_and_get_name(dt, true);
|
||||
if(new_name===dn) {
|
||||
me.load(dt, dn);
|
||||
} else {
|
||||
frappe.set_route("Form", dt, new_name)
|
||||
}
|
||||
fetch_and_render(doctype, name, doctype_layout) {
|
||||
frappe.model.with_doc(doctype, name, (name, r) => {
|
||||
if (r && r['403']) return; // not permitted
|
||||
|
||||
if (!(locals[doctype] && locals[doctype][name])) {
|
||||
if (name && name==='new') {
|
||||
this.render_new_doc(doctype, name, doctype_layout);
|
||||
} else {
|
||||
frappe.show_not_found(route);
|
||||
}
|
||||
return;
|
||||
}
|
||||
me.load(dt, dn);
|
||||
this.render(doctype_layout, name);
|
||||
});
|
||||
}
|
||||
|
||||
load(dt, dn) {
|
||||
frappe.container.change_to("Form/" + dt);
|
||||
frappe.views.formview[dt].frm.refresh(dn);
|
||||
render_new_doc(doctype, name, doctype_layout) {
|
||||
const new_name = frappe.model.make_new_doc_and_get_name(doctype, true);
|
||||
if (new_name===name) {
|
||||
this.render(doctype_layout, name);
|
||||
} else {
|
||||
frappe.set_route("Form", doctype_layout, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
render(doctype_layout, name) {
|
||||
frappe.container.change_to("form/" + doctype_layout);
|
||||
frappe.views.formview[doctype_layout].frm.refresh(name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,8 +339,8 @@ input[type="checkbox"] {
|
|||
|
||||
|
||||
&.disabled-deselected:before {
|
||||
background: #FCFCFD;
|
||||
border: 0.5px solid #E2E6E9;
|
||||
background: $gray-50;
|
||||
border: 0.5px solid var(--gray-400);
|
||||
box-sizing: border-box;
|
||||
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
|
|
@ -348,7 +348,7 @@ input[type="checkbox"] {
|
|||
|
||||
&.disabled-selected:before {
|
||||
content: url("data: image/svg+xml;utf8, <svg width='8' height='7' viewBox='0 0 8 7' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M1 4.00001L2.66667 5.80001L7 1.20001' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
|
||||
background: $gray-50;
|
||||
background: $gray-500;
|
||||
box-sizing: border-box;
|
||||
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue