Merge pull request #13036 from prssanna/form-tab-break
feat: Tab Break fieldtype
This commit is contained in:
commit
5bc3492618
22 changed files with 1661 additions and 1421 deletions
59
cypress/fixtures/doctype_with_tab_break.js
Normal file
59
cypress/fixtures/doctype_with_tab_break.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
export default {
|
||||
name: 'Form With Tab Break',
|
||||
custom: 1,
|
||||
actions: [],
|
||||
doctype: 'DocType',
|
||||
engine: 'InnoDB',
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'username',
|
||||
fieldtype: 'Data',
|
||||
label: 'Name',
|
||||
options: 'Name'
|
||||
},
|
||||
{
|
||||
fieldname: 'tab',
|
||||
fieldtype: 'Tab Break',
|
||||
label: 'Tab 2',
|
||||
},
|
||||
{
|
||||
fieldname: 'Phone',
|
||||
fieldtype: 'Data',
|
||||
label: 'Phone',
|
||||
options: 'Phone',
|
||||
reqd: 1
|
||||
},
|
||||
],
|
||||
links: [
|
||||
{
|
||||
"group": "Profile",
|
||||
"link_doctype": "Contact",
|
||||
"link_fieldname": "user"
|
||||
},
|
||||
{
|
||||
"group": "Profile",
|
||||
"link_doctype": "Chat Profile",
|
||||
"link_fieldname": "user"
|
||||
},
|
||||
],
|
||||
modified_by: 'Administrator',
|
||||
module: 'Custom',
|
||||
owner: 'Administrator',
|
||||
permissions: [
|
||||
{
|
||||
create: 1,
|
||||
delete: 1,
|
||||
email: 1,
|
||||
print: 1,
|
||||
read: 1,
|
||||
role: 'System Manager',
|
||||
share: 1,
|
||||
write: 1
|
||||
}
|
||||
],
|
||||
quick_entry: 1,
|
||||
autoname: "format: Test-{####}",
|
||||
sort_field: 'modified',
|
||||
sort_order: 'ASC',
|
||||
track_changes: 1
|
||||
};
|
||||
31
cypress/integration/form_tab_break.js
Normal file
31
cypress/integration/form_tab_break.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import doctype_with_tab_break from '../fixtures/doctype_with_tab_break';
|
||||
const doctype_name = doctype_with_tab_break.name;
|
||||
context("Form Tab Break", () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit('/app/website');
|
||||
return cy.insert_doc('DocType', doctype_with_tab_break, true);
|
||||
});
|
||||
it("Should switch tab and open correct tabs on validation error", () => {
|
||||
cy.new_form(doctype_name);
|
||||
// test tab switch
|
||||
cy.findByRole("tab", {name: "Tab 2"}).click();
|
||||
cy.findByText("Phone");
|
||||
cy.findByRole("tab", {name: "Details"}).click();
|
||||
cy.findByText("Name");
|
||||
|
||||
// form should switch to the tab with un-filled mandatory field
|
||||
cy.fill_field("username", "Test");
|
||||
cy.findByRole("button", {name: "Save"}).click();
|
||||
cy.findByText("Missing Fields");
|
||||
cy.hide_dialog();
|
||||
cy.findByText("Phone");
|
||||
cy.fill_field("phone", "12345678");
|
||||
cy.findByRole("button", {name: "Save"}).click();
|
||||
|
||||
// After save, first tab should have dashboard
|
||||
cy.get(".form-tabs > .nav-item").eq(0).click();
|
||||
cy.findByText("Connections");
|
||||
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -274,6 +274,8 @@ class DocType(Document):
|
|||
d.fieldname = d.fieldname + '_section'
|
||||
elif d.fieldtype=='Column Break':
|
||||
d.fieldname = d.fieldname + '_column'
|
||||
elif d.fieldtype=='Tab Break':
|
||||
d.fieldname = d.fieldname + '_tab'
|
||||
else:
|
||||
d.fieldname = d.fieldtype.lower().replace(" ","_") + "_" + str(d.idx)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,460 +1,458 @@
|
|||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"creation": "2013-01-10 16:34:01",
|
||||
"description": "Adds a custom field to a DocType",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"dt",
|
||||
"module",
|
||||
"label",
|
||||
"label_help",
|
||||
"fieldname",
|
||||
"insert_after",
|
||||
"length",
|
||||
"column_break_6",
|
||||
"fieldtype",
|
||||
"precision",
|
||||
"hide_seconds",
|
||||
"hide_days",
|
||||
"options",
|
||||
"fetch_from",
|
||||
"fetch_if_empty",
|
||||
"options_help",
|
||||
"section_break_11",
|
||||
"collapsible",
|
||||
"collapsible_depends_on",
|
||||
"default",
|
||||
"depends_on",
|
||||
"mandatory_depends_on",
|
||||
"read_only_depends_on",
|
||||
"properties",
|
||||
"non_negative",
|
||||
"reqd",
|
||||
"unique",
|
||||
"read_only",
|
||||
"ignore_user_permissions",
|
||||
"hidden",
|
||||
"print_hide",
|
||||
"print_hide_if_no_value",
|
||||
"print_width",
|
||||
"no_copy",
|
||||
"allow_on_submit",
|
||||
"in_list_view",
|
||||
"in_standard_filter",
|
||||
"in_global_search",
|
||||
"in_preview",
|
||||
"bold",
|
||||
"report_hide",
|
||||
"search_index",
|
||||
"allow_in_quick_entry",
|
||||
"ignore_xss_filter",
|
||||
"translatable",
|
||||
"hide_border",
|
||||
"description",
|
||||
"permlevel",
|
||||
"width",
|
||||
"columns"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"bold": 1,
|
||||
"fieldname": "dt",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Document",
|
||||
"oldfieldname": "dt",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"bold": 1,
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"label": "Label",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "label",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"fieldname": "label_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Label Help",
|
||||
"oldfieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"fieldname": "fieldname",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Fieldname",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "fieldname",
|
||||
"oldfieldtype": "Data",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"description": "Select the label after which you want to insert new field.",
|
||||
"fieldname": "insert_after",
|
||||
"fieldtype": "Select",
|
||||
"label": "Insert After",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "insert_after",
|
||||
"oldfieldtype": "Select"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"bold": 1,
|
||||
"default": "Data",
|
||||
"fieldname": "fieldtype",
|
||||
"fieldtype": "Select",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Field Type",
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)",
|
||||
"description": "Set non-standard precision for a Float or Currency field",
|
||||
"fieldname": "precision",
|
||||
"fieldtype": "Select",
|
||||
"label": "Precision",
|
||||
"options": "\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9"
|
||||
},
|
||||
{
|
||||
"fieldname": "options",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Options",
|
||||
"oldfieldname": "options",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "fetch_from",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Fetch From"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.",
|
||||
"fieldname": "fetch_if_empty",
|
||||
"fieldtype": "Check",
|
||||
"label": "Fetch If Empty"
|
||||
},
|
||||
{
|
||||
"fieldname": "options_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Options Help",
|
||||
"oldfieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype==\"Section Break\"",
|
||||
"fieldname": "collapsible",
|
||||
"fieldtype": "Check",
|
||||
"label": "Collapsible"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.fieldtype==\"Section Break\"",
|
||||
"fieldname": "collapsible_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Collapsible Depends On"
|
||||
},
|
||||
{
|
||||
"fieldname": "default",
|
||||
"fieldtype": "Text",
|
||||
"label": "Default Value",
|
||||
"oldfieldname": "default",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"label": "Field Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
"print_width": "300px",
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "permlevel",
|
||||
"fieldtype": "Int",
|
||||
"label": "Permission Level",
|
||||
"oldfieldname": "permlevel",
|
||||
"oldfieldtype": "Int"
|
||||
},
|
||||
{
|
||||
"fieldname": "width",
|
||||
"fieldtype": "Data",
|
||||
"label": "Width",
|
||||
"oldfieldname": "width",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)",
|
||||
"fieldname": "columns",
|
||||
"fieldtype": "Int",
|
||||
"label": "Columns"
|
||||
},
|
||||
{
|
||||
"fieldname": "properties",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"print_width": "50%",
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "reqd",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Is Mandatory Field",
|
||||
"oldfieldname": "reqd",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "unique",
|
||||
"fieldtype": "Check",
|
||||
"label": "Unique"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "read_only",
|
||||
"fieldtype": "Check",
|
||||
"label": "Read Only"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype===\"Link\"",
|
||||
"fieldname": "ignore_user_permissions",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore User Permissions"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "hidden",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hidden"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "print_hide",
|
||||
"fieldtype": "Check",
|
||||
"label": "Print Hide",
|
||||
"oldfieldname": "print_hide",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1",
|
||||
"fieldname": "print_hide_if_no_value",
|
||||
"fieldtype": "Check",
|
||||
"label": "Print Hide If No Value"
|
||||
},
|
||||
{
|
||||
"fieldname": "print_width",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Print Width",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "no_copy",
|
||||
"fieldtype": "Check",
|
||||
"label": "No Copy",
|
||||
"oldfieldname": "no_copy",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "allow_on_submit",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow on Submit",
|
||||
"oldfieldname": "allow_on_submit",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "in_list_view",
|
||||
"fieldtype": "Check",
|
||||
"label": "In List View"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "in_standard_filter",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Standard Filter"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)",
|
||||
"fieldname": "in_global_search",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Global Search"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "bold",
|
||||
"fieldtype": "Check",
|
||||
"label": "Bold"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "report_hide",
|
||||
"fieldtype": "Check",
|
||||
"label": "Report Hide",
|
||||
"oldfieldname": "report_hide",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "search_index",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Index",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Don't HTML Encode HTML tags like <script> or just characters like < or >, as they could be intentionally used in this field",
|
||||
"fieldname": "ignore_xss_filter",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore XSS Filter"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)",
|
||||
"fieldname": "translatable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Translatable"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image', 'Int'], doc.fieldtype)",
|
||||
"fieldname": "length",
|
||||
"fieldtype": "Int",
|
||||
"label": "Length"
|
||||
},
|
||||
{
|
||||
"fieldname": "mandatory_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Mandatory Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"fieldname": "read_only_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Read Only Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "allow_in_quick_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow in Quick Entry"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!in_list(['Table', 'Table MultiSelect'], doc.fieldtype);",
|
||||
"fieldname": "in_preview",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Preview"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Duration'",
|
||||
"fieldname": "hide_seconds",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Seconds"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Duration'",
|
||||
"fieldname": "hide_days",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Days"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Section Break'",
|
||||
"fieldname": "hide_border",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Border"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:in_list([\"Int\", \"Float\", \"Currency\"], doc.fieldtype)",
|
||||
"fieldname": "non_negative",
|
||||
"fieldtype": "Check",
|
||||
"label": "Non Negative"
|
||||
},
|
||||
{
|
||||
"fieldname": "module",
|
||||
"fieldtype": "Link",
|
||||
"label": "Module (for export)",
|
||||
"options": "Module Def"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-glass",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-09-04 12:45:22.810120",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Custom Field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "dt,label,fieldtype,options",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"creation": "2013-01-10 16:34:01",
|
||||
"description": "Adds a custom field to a DocType",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"dt",
|
||||
"module",
|
||||
"label",
|
||||
"label_help",
|
||||
"fieldname",
|
||||
"insert_after",
|
||||
"length",
|
||||
"column_break_6",
|
||||
"fieldtype",
|
||||
"precision",
|
||||
"hide_seconds",
|
||||
"hide_days",
|
||||
"options",
|
||||
"fetch_from",
|
||||
"fetch_if_empty",
|
||||
"options_help",
|
||||
"section_break_11",
|
||||
"collapsible",
|
||||
"collapsible_depends_on",
|
||||
"default",
|
||||
"depends_on",
|
||||
"mandatory_depends_on",
|
||||
"read_only_depends_on",
|
||||
"properties",
|
||||
"non_negative",
|
||||
"reqd",
|
||||
"unique",
|
||||
"read_only",
|
||||
"ignore_user_permissions",
|
||||
"hidden",
|
||||
"print_hide",
|
||||
"print_hide_if_no_value",
|
||||
"print_width",
|
||||
"no_copy",
|
||||
"allow_on_submit",
|
||||
"in_list_view",
|
||||
"in_standard_filter",
|
||||
"in_global_search",
|
||||
"in_preview",
|
||||
"bold",
|
||||
"report_hide",
|
||||
"search_index",
|
||||
"allow_in_quick_entry",
|
||||
"ignore_xss_filter",
|
||||
"translatable",
|
||||
"hide_border",
|
||||
"description",
|
||||
"permlevel",
|
||||
"width",
|
||||
"columns"
|
||||
],
|
||||
"fields": [{
|
||||
"bold": 1,
|
||||
"fieldname": "dt",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Document",
|
||||
"oldfieldname": "dt",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"bold": 1,
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"label": "Label",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "label",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"fieldname": "label_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Label Help",
|
||||
"oldfieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"fieldname": "fieldname",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Fieldname",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "fieldname",
|
||||
"oldfieldtype": "Data",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"description": "Select the label after which you want to insert new field.",
|
||||
"fieldname": "insert_after",
|
||||
"fieldtype": "Select",
|
||||
"label": "Insert After",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "insert_after",
|
||||
"oldfieldtype": "Select"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"bold": 1,
|
||||
"default": "Data",
|
||||
"fieldname": "fieldtype",
|
||||
"fieldtype": "Select",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Field Type",
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature\nTab Break",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)",
|
||||
"description": "Set non-standard precision for a Float or Currency field",
|
||||
"fieldname": "precision",
|
||||
"fieldtype": "Select",
|
||||
"label": "Precision",
|
||||
"options": "\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9"
|
||||
},
|
||||
{
|
||||
"fieldname": "options",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Options",
|
||||
"oldfieldname": "options",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "fetch_from",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Fetch From"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.",
|
||||
"fieldname": "fetch_if_empty",
|
||||
"fieldtype": "Check",
|
||||
"label": "Fetch If Empty"
|
||||
},
|
||||
{
|
||||
"fieldname": "options_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Options Help",
|
||||
"oldfieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype==\"Section Break\"",
|
||||
"fieldname": "collapsible",
|
||||
"fieldtype": "Check",
|
||||
"label": "Collapsible"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.fieldtype==\"Section Break\"",
|
||||
"fieldname": "collapsible_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Collapsible Depends On"
|
||||
},
|
||||
{
|
||||
"fieldname": "default",
|
||||
"fieldtype": "Text",
|
||||
"label": "Default Value",
|
||||
"oldfieldname": "default",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"label": "Field Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
"print_width": "300px",
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "permlevel",
|
||||
"fieldtype": "Int",
|
||||
"label": "Permission Level",
|
||||
"oldfieldname": "permlevel",
|
||||
"oldfieldtype": "Int"
|
||||
},
|
||||
{
|
||||
"fieldname": "width",
|
||||
"fieldtype": "Data",
|
||||
"label": "Width",
|
||||
"oldfieldname": "width",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)",
|
||||
"fieldname": "columns",
|
||||
"fieldtype": "Int",
|
||||
"label": "Columns"
|
||||
},
|
||||
{
|
||||
"fieldname": "properties",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"print_width": "50%",
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "reqd",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Is Mandatory Field",
|
||||
"oldfieldname": "reqd",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "unique",
|
||||
"fieldtype": "Check",
|
||||
"label": "Unique"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "read_only",
|
||||
"fieldtype": "Check",
|
||||
"label": "Read Only"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype===\"Link\"",
|
||||
"fieldname": "ignore_user_permissions",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore User Permissions"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "hidden",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hidden"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "print_hide",
|
||||
"fieldtype": "Check",
|
||||
"label": "Print Hide",
|
||||
"oldfieldname": "print_hide",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1",
|
||||
"fieldname": "print_hide_if_no_value",
|
||||
"fieldtype": "Check",
|
||||
"label": "Print Hide If No Value"
|
||||
},
|
||||
{
|
||||
"fieldname": "print_width",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Print Width",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "no_copy",
|
||||
"fieldtype": "Check",
|
||||
"label": "No Copy",
|
||||
"oldfieldname": "no_copy",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "allow_on_submit",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow on Submit",
|
||||
"oldfieldname": "allow_on_submit",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "in_list_view",
|
||||
"fieldtype": "Check",
|
||||
"label": "In List View"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "in_standard_filter",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Standard Filter"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)",
|
||||
"fieldname": "in_global_search",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Global Search"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "bold",
|
||||
"fieldtype": "Check",
|
||||
"label": "Bold"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "report_hide",
|
||||
"fieldtype": "Check",
|
||||
"label": "Report Hide",
|
||||
"oldfieldname": "report_hide",
|
||||
"oldfieldtype": "Check"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "search_index",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Index",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Don't HTML Encode HTML tags like <script> or just characters like < or >, as they could be intentionally used in this field",
|
||||
"fieldname": "ignore_xss_filter",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore XSS Filter"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)",
|
||||
"fieldname": "translatable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Translatable"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image', 'Int'], doc.fieldtype)",
|
||||
"fieldname": "length",
|
||||
"fieldtype": "Int",
|
||||
"label": "Length"
|
||||
},
|
||||
{
|
||||
"fieldname": "mandatory_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Mandatory Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"fieldname": "read_only_depends_on",
|
||||
"fieldtype": "Code",
|
||||
"label": "Read Only Depends On",
|
||||
"length": 255
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "allow_in_quick_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow in Quick Entry"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!in_list(['Table', 'Table MultiSelect'], doc.fieldtype);",
|
||||
"fieldname": "in_preview",
|
||||
"fieldtype": "Check",
|
||||
"label": "In Preview"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Duration'",
|
||||
"fieldname": "hide_seconds",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Seconds"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Duration'",
|
||||
"fieldname": "hide_days",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Days"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.fieldtype=='Section Break'",
|
||||
"fieldname": "hide_border",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Border"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:in_list([\"Int\", \"Float\", \"Currency\"], doc.fieldtype)",
|
||||
"fieldname": "non_negative",
|
||||
"fieldtype": "Check",
|
||||
"label": "Non Negative"
|
||||
},
|
||||
{
|
||||
"fieldname": "module",
|
||||
"fieldtype": "Link",
|
||||
"label": "Module (for export)",
|
||||
"options": "Module Def"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-glass",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-09-04 12:45:23.810120",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Custom Field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "dt,label,fieldtype,options",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ class CustomField(Document):
|
|||
if not self.fieldname:
|
||||
label = self.label
|
||||
if not label:
|
||||
if self.fieldtype in ["Section Break", "Column Break"]:
|
||||
if self.fieldtype in ["Section Break", "Column Break", "Tab Break"]:
|
||||
label = self.fieldtype + "_" + str(self.idx)
|
||||
else:
|
||||
frappe.throw(_("Label is mandatory"))
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
"label": "Type",
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSignature\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime",
|
||||
"options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSignature\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nTab Break",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
|
|
@ -428,7 +428,7 @@
|
|||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-10 21:57:24.479749",
|
||||
"modified": "2021-07-11 21:57:24.479749",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Customize Form Field",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class PropertySetter(Document):
|
|||
fields=['fieldname', 'label', 'fieldtype'],
|
||||
filters={
|
||||
'parent': dt,
|
||||
'fieldtype': ['not in', ('Section Break', 'Column Break', 'HTML', 'Read Only', 'Fold') + frappe.model.table_fields],
|
||||
'fieldtype': ['not in', ('Section Break', 'Column Break', 'Tab Break', 'HTML', 'Read Only', 'Fold') + frappe.model.table_fields],
|
||||
'fieldname': ['!=', '']
|
||||
},
|
||||
order_by='label asc',
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ data_fieldtypes = (
|
|||
no_value_fields = (
|
||||
'Section Break',
|
||||
'Column Break',
|
||||
'Tab Break',
|
||||
'HTML',
|
||||
'Table',
|
||||
'Table MultiSelect',
|
||||
|
|
@ -53,6 +54,7 @@ no_value_fields = (
|
|||
display_fieldtypes = (
|
||||
'Section Break',
|
||||
'Column Break',
|
||||
'Tab Break',
|
||||
'HTML',
|
||||
'Button',
|
||||
'Image',
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ frappe.PrintFormatBuilder = class PrintFormatBuilder {
|
|||
} else if(f.fieldtype==="Column Break") {
|
||||
set_column();
|
||||
|
||||
} else if(!in_list(["Section Break", "Column Break", "Fold"], f.fieldtype)
|
||||
} else if (!in_list(["Section Break", "Column Break", "Tab Break", "Fold"], f.fieldtype)
|
||||
&& f.label) {
|
||||
if(!column) set_column();
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ frappe.PrintFormatBuilder = class PrintFormatBuilder {
|
|||
init_visible_columns(f) {
|
||||
f.visible_columns = []
|
||||
$.each(frappe.get_meta(f.options).fields, function(i, _f) {
|
||||
if(!in_list(["Section Break", "Column Break"], _f.fieldtype) &&
|
||||
if (!in_list(["Section Break", "Column Break", "Tab Break"], _f.fieldtype) &&
|
||||
!_f.print_hide && f.label) {
|
||||
|
||||
// column names set as fieldname|width
|
||||
|
|
@ -606,7 +606,7 @@ frappe.PrintFormatBuilder = class PrintFormatBuilder {
|
|||
// add remaining fields
|
||||
$.each(doc_fields, function(j, f) {
|
||||
if (f && !in_list(column_names, f.fieldname)
|
||||
&& !in_list(["Section Break", "Column Break"], f.fieldtype) && f.label) {
|
||||
&& !in_list(["Section Break", "Column Break", "Tab Break"], f.fieldtype) && f.label) {
|
||||
fields.push(f);
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</div>
|
||||
<div class="print-format-builder-sidebar-fields">
|
||||
{% for (var i=0, l=fields.length; i < l; i++) { var f = fields[i]; %}
|
||||
{% if(!in_list(["Section Break", "Column Break", "Fold"], f.fieldtype)) { %}
|
||||
{% if(!in_list(["Section Break", "Tab Break", "Column Break", "Fold"], f.fieldtype)) { %}
|
||||
<div class="print-format-builder-field-placeholder"
|
||||
data-fieldname="{%= f.fieldname %}">
|
||||
<div title="{{f.label}}" class="field-label btn btn-default btn-sm sidebar-field ellipsis
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ import "./frappe/ui/slides.js";
|
|||
import "./frappe/ui/find.js";
|
||||
import "./frappe/ui/iconbar.js";
|
||||
import "./frappe/form/layout.js";
|
||||
import "./frappe/form/section.js";
|
||||
import "./frappe/form/tab.js";
|
||||
import "./frappe/form/column.js";
|
||||
import "./frappe/ui/field_group.js";
|
||||
import "./frappe/form/link_selector.js";
|
||||
import "./frappe/form/multi_select_dialog.js";
|
||||
|
|
|
|||
49
frappe/public/js/frappe/form/column.js
Normal file
49
frappe/public/js/frappe/form/column.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
export default class Column {
|
||||
constructor(section, df) {
|
||||
if (!df) df = {};
|
||||
|
||||
this.df = df;
|
||||
this.section = section;
|
||||
this.make();
|
||||
this.resize_all_columns();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.wrapper = $(`
|
||||
<div class="form-column">
|
||||
<form>
|
||||
</form>
|
||||
</div>
|
||||
`)
|
||||
.appendTo(this.section.body)
|
||||
.find("form")
|
||||
.on("submit", function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (this.df.label) {
|
||||
$(`
|
||||
<label class="control-label">
|
||||
${__(this.df.label)}
|
||||
</label>
|
||||
`)
|
||||
.appendTo(this.wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
resize_all_columns() {
|
||||
// distribute all columns equally
|
||||
let colspan = cint(12 / this.section.wrapper.find(".form-column").length);
|
||||
|
||||
this.section.wrapper
|
||||
.find(".form-column")
|
||||
.removeClass()
|
||||
.addClass("form-column")
|
||||
.addClass("col-sm-" + colspan);
|
||||
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.section.refresh();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +1,65 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
import Section from "./section.js";
|
||||
|
||||
frappe.ui.form.Dashboard = class FormDashboard {
|
||||
constructor(opts) {
|
||||
$.extend(this, opts);
|
||||
constructor(parent, frm) {
|
||||
this.parent = parent;
|
||||
this.frm = frm;
|
||||
this.setup_dashboard_sections();
|
||||
}
|
||||
|
||||
setup_dashboard_sections() {
|
||||
this.progress_area = new Section(this.parent, {
|
||||
this.progress_area = this.make_section({
|
||||
css_class: 'progress-area',
|
||||
hidden: 1,
|
||||
collapsible: 1
|
||||
is_dashboard_section: 1,
|
||||
});
|
||||
|
||||
this.heatmap_area = new Section(this.parent, {
|
||||
title: __("Overview"),
|
||||
this.heatmap_area = this.make_section({
|
||||
label: __("Overview"),
|
||||
css_class: 'form-heatmap',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
is_dashboard_section: 1,
|
||||
body_html: `
|
||||
<div id="heatmap-${frappe.model.scrub(this.frm.doctype)}" class="heatmap"></div>
|
||||
<div class="text-muted small heatmap-message hidden"></div>
|
||||
`
|
||||
});
|
||||
|
||||
this.chart_area = new Section(this.parent, {
|
||||
title: __("Graph"),
|
||||
this.chart_area = this.make_section({
|
||||
label: __("Graph"),
|
||||
css_class: 'form-graph',
|
||||
hidden: 1,
|
||||
collapsible: 1
|
||||
is_dashboard_section: 1
|
||||
});
|
||||
|
||||
this.stats_area_row = $(`<div class="row"></div>`);
|
||||
this.stats_area = new Section(this.parent, {
|
||||
title: __("Stats"),
|
||||
this.stats_area = this.make_section({
|
||||
label: __("Stats"),
|
||||
css_class: 'form-stats',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
is_dashboard_section: 1,
|
||||
body_html: this.stats_area_row
|
||||
});
|
||||
|
||||
this.transactions_area = $(`<div class="transactions"></div`);
|
||||
this.links_area = new Section(this.parent, {
|
||||
title: __("Connections"),
|
||||
|
||||
this.links_area = this.make_section({
|
||||
label: __("Connections"),
|
||||
css_class: 'form-links',
|
||||
hidden: 1,
|
||||
collapsible: 1,
|
||||
is_dashboard_section: 1,
|
||||
body_html: this.transactions_area
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
make_section(df) {
|
||||
return new Section(this.parent, df);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.hide();
|
||||
|
||||
// clear progress
|
||||
this.progress_area.body.empty();
|
||||
this.progress_area.hide();
|
||||
|
|
@ -70,19 +74,19 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
|
||||
// clear custom
|
||||
this.parent.find('.custom').remove();
|
||||
this.hide();
|
||||
// this.hide();
|
||||
}
|
||||
|
||||
add_section(body_html, title=null, css_class="custom", hidden=false) {
|
||||
add_section(body_html, label=null, css_class="custom", hidden=false) {
|
||||
let options = {
|
||||
title,
|
||||
label,
|
||||
css_class,
|
||||
hidden,
|
||||
body_html,
|
||||
make_card: true,
|
||||
collapsible: 1
|
||||
is_dashboard_section: 1
|
||||
};
|
||||
return new Section(this.parent, options).body;
|
||||
return new Section(this.frm.layout.wrapper, options).body;
|
||||
}
|
||||
|
||||
add_progress(title, percent, message) {
|
||||
|
|
@ -154,7 +158,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
|
||||
make_progress_chart(title) {
|
||||
this.progress_area.show();
|
||||
var progress_chart = $('<div class="progress-chart" title="'+(title || '')+'"></div>')
|
||||
let progress_chart = $('<div class="progress-chart" title="'+(title || '')+'"></div>')
|
||||
.appendTo(this.progress_area.body);
|
||||
return progress_chart;
|
||||
}
|
||||
|
|
@ -169,7 +173,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
this.init_data();
|
||||
}
|
||||
|
||||
var show = false;
|
||||
let show = false;
|
||||
|
||||
if (this.data && ((this.data.transactions || []).length
|
||||
|| (this.data.reports || []).length)) {
|
||||
|
|
@ -197,11 +201,10 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
|
||||
after_refresh() {
|
||||
var me = this;
|
||||
// show / hide new buttons (if allowed)
|
||||
this.links_area.body.find('.btn-new').each(function() {
|
||||
if (me.frm.can_create($(this).attr('data-doctype'))) {
|
||||
$(this).removeClass('hidden');
|
||||
this.links_area.body.find('.btn-new').each((i, el) => {
|
||||
if (this.frm.can_create($(this).attr('data-doctype'))) {
|
||||
$(el).removeClass('hidden');
|
||||
}
|
||||
});
|
||||
!this.frm.is_new() && this.set_open_count();
|
||||
|
|
@ -269,7 +272,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
|
||||
render_links() {
|
||||
var me = this;
|
||||
let me = this;
|
||||
this.links_area.show();
|
||||
this.links_area.body.find('.btn-new').addClass('hidden');
|
||||
if (this.data_rendered) {
|
||||
|
|
@ -329,7 +332,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
|
||||
open_document_list($link, show_open) {
|
||||
// show document list with filters
|
||||
var doctype = $link.attr('data-doctype'),
|
||||
let doctype = $link.attr('data-doctype'),
|
||||
names = $link.attr('data-names') || [];
|
||||
|
||||
if (this.data.internal_links[doctype]) {
|
||||
|
|
@ -351,8 +354,8 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
get_document_filter(doctype) {
|
||||
// return the default filter for the given document
|
||||
// like {"customer": frm.doc.name}
|
||||
var filter = {};
|
||||
var fieldname = this.data.non_standard_fieldnames
|
||||
let filter = {};
|
||||
let fieldname = this.data.non_standard_fieldnames
|
||||
? (this.data.non_standard_fieldnames[doctype] || this.data.fieldname)
|
||||
: this.data.fieldname;
|
||||
|
||||
|
|
@ -371,7 +374,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
|
||||
// list all items from the transaction list
|
||||
var items = [],
|
||||
let items = [],
|
||||
me = this;
|
||||
|
||||
this.data.transactions.forEach(function(group) {
|
||||
|
|
@ -380,7 +383,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
});
|
||||
});
|
||||
|
||||
var method = this.data.method || 'frappe.desk.notifications.get_open_count';
|
||||
let method = this.data.method || 'frappe.desk.notifications.get_open_count';
|
||||
frappe.call({
|
||||
type: "GET",
|
||||
method: method,
|
||||
|
|
@ -429,7 +432,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
|
||||
set_badge_count(doctype, open_count, count, names) {
|
||||
var $link = $(this.transactions_area)
|
||||
let $link = $(this.transactions_area)
|
||||
.find('.document-link[data-doctype="'+doctype+'"]');
|
||||
|
||||
if (open_count) {
|
||||
|
|
@ -476,7 +479,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
this.heatmap_area.body.find('svg').css({'margin': 'auto'});
|
||||
|
||||
// message
|
||||
var heatmap_message = this.heatmap_area.body.find('.heatmap-message');
|
||||
let heatmap_message = this.heatmap_area.body.find('.heatmap-message');
|
||||
if (this.data.heatmap_message) {
|
||||
heatmap_message.removeClass('hidden').html(this.data.heatmap_message);
|
||||
} else {
|
||||
|
|
@ -491,9 +494,9 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
|
||||
|
||||
// set colspan
|
||||
var indicators = this.stats_area_row.find('.indicator-column');
|
||||
var n_indicators = indicators.length + 1;
|
||||
var colspan;
|
||||
let indicators = this.stats_area_row.find('.indicator-column');
|
||||
let n_indicators = indicators.length + 1;
|
||||
let colspan;
|
||||
if (n_indicators > 4) {
|
||||
colspan = 3;
|
||||
} else {
|
||||
|
|
@ -505,7 +508,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
indicators.removeClass().addClass('col-sm-'+colspan).addClass('indicator-column');
|
||||
}
|
||||
|
||||
var indicator = $('<div class="col-sm-'+colspan+' indicator-column"><span class="indicator '+color+'">'
|
||||
let indicator = $('<div class="col-sm-'+colspan+' indicator-column"><span class="indicator '+color+'">'
|
||||
+label+'</span></div>').appendTo(this.stats_area_row);
|
||||
|
||||
return indicator;
|
||||
|
|
@ -513,9 +516,9 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
|
||||
// graphs
|
||||
setup_graph() {
|
||||
var me = this;
|
||||
var method = this.data.graph_method;
|
||||
var args = {
|
||||
let me = this;
|
||||
let method = this.data.graph_method;
|
||||
let args = {
|
||||
doctype: this.frm.doctype,
|
||||
docname: this.frm.doc.name,
|
||||
};
|
||||
|
|
@ -579,11 +582,10 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
|
||||
add_comment(text, alert_class, permanent) {
|
||||
var me = this;
|
||||
this.set_headline_alert(text, alert_class);
|
||||
if (!permanent) {
|
||||
setTimeout(function() {
|
||||
me.clear_headline();
|
||||
setTimeout(() => {
|
||||
this.clear_headline();
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
|
@ -600,109 +602,3 @@ frappe.ui.form.Dashboard = class FormDashboard {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Section {
|
||||
constructor(parent, options) {
|
||||
this.parent = parent;
|
||||
this.df = options || {};
|
||||
this.make();
|
||||
|
||||
if (this.df.title && this.df.collapsible && localStorage.getItem(options.css_class + '-closed')) {
|
||||
this.collapse();
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.wrapper = $(`<div class="form-dashboard-section ${ this.df.make_card ? "card-section" : "" }">`)
|
||||
.appendTo(this.parent);
|
||||
|
||||
if (this.df) {
|
||||
if (this.df.title) {
|
||||
this.make_head();
|
||||
}
|
||||
if (this.df.description) {
|
||||
this.description_wrapper = $(
|
||||
`<div class="col-sm-12 form-section-description">
|
||||
${__(this.df.description)}
|
||||
</div>`
|
||||
);
|
||||
|
||||
this.wrapper.append(this.description_wrapper);
|
||||
}
|
||||
if (this.df.css_class) {
|
||||
this.wrapper.addClass(this.df.css_class);
|
||||
}
|
||||
if (this.df.hide_border) {
|
||||
this.wrapper.toggleClass("hide-border", true);
|
||||
}
|
||||
}
|
||||
|
||||
this.body = $('<div class="section-body">').appendTo(this.wrapper);
|
||||
|
||||
if (this.df.body_html) {
|
||||
this.body.append(this.df.body_html);
|
||||
}
|
||||
}
|
||||
|
||||
make_head() {
|
||||
this.head = $(`
|
||||
<div class="section-head">
|
||||
${__(this.df.title)}
|
||||
<span class="ml-2 collapse-indicator mb-1"></span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
this.head.appendTo(this.wrapper);
|
||||
this.indicator = this.head.find('.collapse-indicator');
|
||||
this.indicator.hide();
|
||||
|
||||
if (this.df.collapsible) {
|
||||
// show / hide based on status
|
||||
this.collapse_link = this.head.on("click", () => {
|
||||
this.collapse();
|
||||
});
|
||||
this.set_icon();
|
||||
this.indicator.show();
|
||||
}
|
||||
}
|
||||
|
||||
refresh() {
|
||||
if (!this.df) return;
|
||||
|
||||
// hide if explicitly hidden
|
||||
let hide = this.df.hidden;
|
||||
this.wrapper.toggle(!hide);
|
||||
}
|
||||
|
||||
collapse(hide) {
|
||||
if (hide === undefined) {
|
||||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
this.body.toggleClass("hide", hide);
|
||||
this.head && this.head.toggleClass("collapsed", hide);
|
||||
|
||||
this.set_icon(hide);
|
||||
|
||||
// save state for next reload ('' is falsy)
|
||||
localStorage.setItem(this.df.css_class + '-closed', hide ? '1' : '');
|
||||
}
|
||||
|
||||
set_icon(hide) {
|
||||
let indicator_icon = hide ? 'down' : 'up-line';
|
||||
this.indicator && this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));
|
||||
}
|
||||
|
||||
is_collapsed() {
|
||||
return this.body.hasClass('hide');
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.wrapper.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
this.wrapper.show();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,11 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.watch_model_updates();
|
||||
|
||||
if (!this.meta.hide_toolbar && frappe.boot.desk_settings.timeline) {
|
||||
// this.footer_tab = new frappe.ui.form.Tab(this.layout, {
|
||||
// label: __("Activity"),
|
||||
// fieldname: 'timeline'
|
||||
// });
|
||||
|
||||
this.footer = new frappe.ui.form.Footer({
|
||||
frm: this,
|
||||
parent: $('<div>').appendTo(this.page.main.parent())
|
||||
|
|
@ -128,8 +133,8 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
}
|
||||
|
||||
setup_std_layout() {
|
||||
this.form_wrapper = $('<div></div>').appendTo(this.layout_main);
|
||||
this.body = $('<div></div>').appendTo(this.form_wrapper);
|
||||
this.form_wrapper = $('<div></div>').appendTo(this.layout_main);
|
||||
this.body = $('<div></div>').appendTo(this.form_wrapper);
|
||||
|
||||
// only tray
|
||||
this.meta.section_style='Simple'; // always simple!
|
||||
|
|
@ -141,17 +146,19 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
doctype_layout: this.doctype_layout,
|
||||
frm: this,
|
||||
with_dashboard: true,
|
||||
card_layout: true,
|
||||
card_layout: true
|
||||
});
|
||||
|
||||
this.layout.make();
|
||||
|
||||
this.fields_dict = this.layout.fields_dict;
|
||||
this.fields = this.layout.fields_list;
|
||||
|
||||
this.dashboard = new frappe.ui.form.Dashboard({
|
||||
frm: this,
|
||||
parent: $('<div class="form-dashboard">').insertAfter(this.layout.wrapper.find('.form-message'))
|
||||
});
|
||||
let dashboard_parent = $('<div class="form-dashboard">');
|
||||
|
||||
let main_page = this.layout.tabs.length ? this.layout.tabs[0].wrapper : this.layout.wrapper;
|
||||
main_page.prepend(dashboard_parent);
|
||||
this.dashboard = new frappe.ui.form.Dashboard(dashboard_parent, this);
|
||||
|
||||
this.tour = new frappe.ui.form.FormTour({
|
||||
frm: this
|
||||
|
|
@ -458,7 +465,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
},
|
||||
() => this.cscript.is_onload && this.is_new() && this.focus_on_first_input(),
|
||||
() => this.run_after_load_hook(),
|
||||
() => this.dashboard.after_refresh()
|
||||
() => this.dashboard.after_refresh(),
|
||||
]);
|
||||
|
||||
} else {
|
||||
|
|
@ -467,6 +474,8 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
|
||||
this.$wrapper.trigger('render_complete');
|
||||
|
||||
this.cscript.is_onload && this.set_first_tab_as_active();
|
||||
|
||||
if(!this.hidden) {
|
||||
this.layout.show_empty_form_message();
|
||||
}
|
||||
|
|
@ -474,6 +483,11 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
this.scroll_to_element();
|
||||
}
|
||||
|
||||
set_first_tab_as_active() {
|
||||
this.layout.tabs[0]
|
||||
&& this.layout.tabs[0].set_active();
|
||||
}
|
||||
|
||||
focus_on_first_input() {
|
||||
let first = this.form_wrapper.find('.form-layout :input:visible:first');
|
||||
if (!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
|
||||
|
|
@ -1604,6 +1618,11 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
|
||||
let $el = field.$wrapper;
|
||||
|
||||
// set tab as active
|
||||
if (field.tab && !field.tab.is_active()) {
|
||||
field.tab.set_active();
|
||||
}
|
||||
|
||||
// uncollapse section
|
||||
if (field.section.is_collapsed()) {
|
||||
field.section.collapse(false);
|
||||
|
|
|
|||
|
|
@ -1,27 +1,50 @@
|
|||
import '../class';
|
||||
import Section from "./section.js";
|
||||
import Tab from "./tab.js";
|
||||
import Column from "./column.js";
|
||||
|
||||
frappe.ui.form.Layout = class Layout {
|
||||
constructor (opts) {
|
||||
this.views = {};
|
||||
this.pages = [];
|
||||
this.tabs = [];
|
||||
this.sections = [];
|
||||
this.fields_list = [];
|
||||
this.fields_dict = {};
|
||||
|
||||
$.extend(this, opts);
|
||||
}
|
||||
|
||||
make() {
|
||||
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);
|
||||
this.page = $('<div class="form-page"></div>').appendTo(this.wrapper);
|
||||
|
||||
if (!this.fields) {
|
||||
this.fields = this.get_doctype_fields();
|
||||
}
|
||||
this.setup_tabbing();
|
||||
|
||||
if (this.is_tabbed_layout()) {
|
||||
this.setup_tabbed_layout();
|
||||
}
|
||||
|
||||
this.setup_tab_events();
|
||||
this.render();
|
||||
}
|
||||
|
||||
setup_tabbed_layout() {
|
||||
$(`
|
||||
<div class="form-tabs-list">
|
||||
<ul class="nav form-tabs" id="form-tabs" role="tablist"></ul>
|
||||
</div>
|
||||
`).appendTo(this.page);
|
||||
this.tabs_list = this.page.find('.form-tabs');
|
||||
this.tabs_content = $(`<div class="form-tab-content tab-content"></div>`).appendTo(this.page);
|
||||
this.setup_events();
|
||||
}
|
||||
|
||||
show_empty_form_message() {
|
||||
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"));
|
||||
|
|
@ -87,49 +110,58 @@ frappe.ui.form.Layout = class Layout {
|
|||
this.message.empty().addClass('hidden');
|
||||
}
|
||||
}
|
||||
render (new_fields) {
|
||||
var me = this;
|
||||
var fields = new_fields || this.fields;
|
||||
|
||||
render(new_fields) {
|
||||
let fields = new_fields || this.fields;
|
||||
|
||||
this.section = null;
|
||||
this.column = null;
|
||||
|
||||
if (this.with_dashboard) {
|
||||
this.setup_dashboard_section();
|
||||
if (this.no_opening_section() && !this.is_tabbed_layout()) {
|
||||
this.fields.unshift({fieldtype: 'Section Break'});
|
||||
}
|
||||
|
||||
if (this.no_opening_section()) {
|
||||
this.make_section();
|
||||
if (this.is_tabbed_layout()) {
|
||||
let default_tab = {label: __('Details'), fieldname: 'details', fieldtype: "Tab Break"};
|
||||
let first_tab = this.fields[1].fieldtype === "Tab Break" ? this.fields[1] : null;
|
||||
if (!first_tab) {
|
||||
this.fields.splice(1, 0, default_tab);
|
||||
}
|
||||
}
|
||||
$.each(fields, function (i, df) {
|
||||
|
||||
fields.forEach(df => {
|
||||
switch (df.fieldtype) {
|
||||
case "Fold":
|
||||
me.make_page(df);
|
||||
this.make_page(df);
|
||||
break;
|
||||
case "Section Break":
|
||||
me.make_section(df);
|
||||
this.make_section(df);
|
||||
break;
|
||||
case "Column Break":
|
||||
me.make_column(df);
|
||||
this.make_column(df);
|
||||
break;
|
||||
case "Tab Break":
|
||||
this.make_tab(df);
|
||||
break;
|
||||
default:
|
||||
me.make_field(df);
|
||||
this.make_field(df);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
no_opening_section () {
|
||||
no_opening_section() {
|
||||
return (this.fields[0] && this.fields[0].fieldtype != "Section Break") || !this.fields.length;
|
||||
}
|
||||
|
||||
setup_dashboard_section () {
|
||||
if (this.no_opening_section()) {
|
||||
this.fields.unshift({fieldtype: 'Section Break'});
|
||||
}
|
||||
no_opening_tab() {
|
||||
return (this.fields[1] && this.fields[1].fieldtype != "Tab Break") || !this.fields.length;
|
||||
}
|
||||
|
||||
replace_field (fieldname, df, render) {
|
||||
is_tabbed_layout() {
|
||||
return this.fields.find(f => f.fieldtype === "Tab Break");
|
||||
}
|
||||
|
||||
replace_field(fieldname, df, render) {
|
||||
df.fieldname = fieldname; // change of fieldname is avoided
|
||||
if (this.fields_dict[fieldname] && this.fields_dict[fieldname].df) {
|
||||
const fieldobj = this.init_field(df, render);
|
||||
|
|
@ -145,7 +177,7 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
}
|
||||
|
||||
make_field (df, colspan, render) {
|
||||
make_field(df, colspan, render) {
|
||||
!this.section && this.make_section();
|
||||
!this.column && this.make_column();
|
||||
|
||||
|
|
@ -159,9 +191,15 @@ frappe.ui.form.Layout = class Layout {
|
|||
this.section.fields_list.push(fieldobj);
|
||||
this.section.fields_dict[df.fieldname] = fieldobj;
|
||||
fieldobj.section = this.section;
|
||||
|
||||
if (this.current_tab) {
|
||||
fieldobj.tab = this.current_tab;
|
||||
this.current_tab.fields_list.push(fieldobj);
|
||||
this.current_tab.fields_dict[df.fieldname] = fieldobj;
|
||||
}
|
||||
}
|
||||
|
||||
init_field (df, render = false) {
|
||||
init_field(df, render=false) {
|
||||
const fieldobj = frappe.ui.form.make_control({
|
||||
df: df,
|
||||
doctype: this.doctype,
|
||||
|
|
@ -176,8 +214,8 @@ frappe.ui.form.Layout = class Layout {
|
|||
return fieldobj;
|
||||
}
|
||||
|
||||
make_page (df) { // eslint-disable-line no-unused-vars
|
||||
var me = this,
|
||||
make_page(df) { // eslint-disable-line no-unused-vars
|
||||
let me = this,
|
||||
head = $('<div class="form-clickable-section text-center">\
|
||||
<a class="btn-fold h6 text-muted">' + __("Show more details") + '</a>\
|
||||
</div>').appendTo(this.wrapper);
|
||||
|
|
@ -185,7 +223,7 @@ frappe.ui.form.Layout = class Layout {
|
|||
this.page = $('<div class="form-page second-page hide"></div>').appendTo(this.wrapper);
|
||||
|
||||
this.fold_btn = head.find(".btn-fold").on("click", function () {
|
||||
var page = $(this).parent().next();
|
||||
let page = $(this).parent().next();
|
||||
if (page.hasClass("hide")) {
|
||||
$(this).removeClass("btn-fold").html(__("Hide details"));
|
||||
page.removeClass("hide");
|
||||
|
|
@ -202,12 +240,12 @@ frappe.ui.form.Layout = class Layout {
|
|||
this.folded = true;
|
||||
}
|
||||
|
||||
unfold () {
|
||||
unfold() {
|
||||
this.fold_btn.trigger('click');
|
||||
}
|
||||
|
||||
make_section (df) {
|
||||
this.section = new frappe.ui.form.Section(this, df);
|
||||
make_section(df) {
|
||||
this.section = new Section(this.current_tab ? this.current_tab.wrapper : this.page, df, this.card_layout);
|
||||
|
||||
// append to layout fields
|
||||
if (df) {
|
||||
|
|
@ -218,15 +256,23 @@ frappe.ui.form.Layout = class Layout {
|
|||
this.column = null;
|
||||
}
|
||||
|
||||
make_column (df) {
|
||||
this.column = new frappe.ui.form.Column(this.section, df);
|
||||
make_column(df) {
|
||||
this.column = new Column(this.section, df);
|
||||
if (df && df.fieldname) {
|
||||
this.fields_list.push(this.column);
|
||||
}
|
||||
}
|
||||
|
||||
refresh (doc) {
|
||||
var me = this;
|
||||
make_tab(df) {
|
||||
this.section = null;
|
||||
let tab = new Tab(this, df, this.frm, this.tabs_list, this.tabs_content);
|
||||
this.current_tab = tab;
|
||||
this.make_section({fieldtype: 'Section Break'});
|
||||
this.tabs.push(tab);
|
||||
return tab;
|
||||
}
|
||||
|
||||
refresh(doc) {
|
||||
if (doc) this.doc = doc;
|
||||
|
||||
if (this.frm) {
|
||||
|
|
@ -234,7 +280,7 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
|
||||
// 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);
|
||||
this.attach_doc_and_docfields(true);
|
||||
|
||||
if (this.frm && this.frm.wrapper) {
|
||||
$(this.frm.wrapper).trigger("refresh-fields");
|
||||
|
|
@ -246,6 +292,9 @@ frappe.ui.form.Layout = class Layout {
|
|||
// refresh sections
|
||||
this.refresh_sections();
|
||||
|
||||
// refresh tabs
|
||||
this.tabbed_layout && this.refresh_tabs();
|
||||
|
||||
if (this.frm) {
|
||||
// collapse sections
|
||||
this.refresh_section_collapse();
|
||||
|
|
@ -277,7 +326,30 @@ frappe.ui.form.Layout = class Layout {
|
|||
});
|
||||
}
|
||||
|
||||
refresh_fields (fields) {
|
||||
refresh_tabs() {
|
||||
this.tabs.forEach(tab => {
|
||||
if (!tab.wrapper.hasClass('hide') || !tab.parent.hasClass('hide')) {
|
||||
tab.parent.removeClass('show hide');
|
||||
tab.wrapper.removeClass('show hide');
|
||||
if (
|
||||
tab.wrapper.find(
|
||||
".form-section:not(.hide-control, .empty-section), .form-dashboard-section:not(.hide-control, .empty-section)"
|
||||
).length
|
||||
) {
|
||||
tab.toggle(true);
|
||||
} else {
|
||||
tab.toggle(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const visible_tabs = this.tabs.filter(tab => !tab.hidden);
|
||||
if (visible_tabs && visible_tabs.length == 1) {
|
||||
visible_tabs[0].parent.toggleClass('hide show');
|
||||
}
|
||||
}
|
||||
|
||||
refresh_fields(fields) {
|
||||
let fieldnames = fields.map((field) => {
|
||||
if (field.fieldname) return field.fieldname;
|
||||
});
|
||||
|
|
@ -292,7 +364,7 @@ frappe.ui.form.Layout = class Layout {
|
|||
});
|
||||
}
|
||||
|
||||
add_fields (fields) {
|
||||
add_fields(fields) {
|
||||
this.render(fields);
|
||||
this.refresh_fields(fields);
|
||||
}
|
||||
|
|
@ -300,11 +372,11 @@ frappe.ui.form.Layout = class Layout {
|
|||
refresh_section_collapse () {
|
||||
if (!(this.sections && this.sections.length)) return;
|
||||
|
||||
for (var i = 0; i < this.sections.length; i++) {
|
||||
var section = this.sections[i];
|
||||
var df = section.df;
|
||||
for (let i = 0; i < this.sections.length; i++) {
|
||||
let section = this.sections[i];
|
||||
let df = section.df;
|
||||
if (df && df.collapsible) {
|
||||
var collapse = true;
|
||||
let collapse = true;
|
||||
|
||||
if (df.collapsible_depends_on) {
|
||||
collapse = !this.evaluate_depends_on_value(df.collapsible_depends_on);
|
||||
|
|
@ -319,10 +391,10 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
}
|
||||
|
||||
attach_doc_and_docfields (refresh) {
|
||||
var me = this;
|
||||
for (var i = 0, l = this.fields_list.length; i < l; i++) {
|
||||
var fieldobj = this.fields_list[i];
|
||||
attach_doc_and_docfields(refresh) {
|
||||
let me = this;
|
||||
for (let i = 0, l = this.fields_list.length; i < l; i++) {
|
||||
let fieldobj = this.fields_list[i];
|
||||
if (me.doc) {
|
||||
fieldobj.doc = me.doc;
|
||||
fieldobj.doctype = me.doc.doctype;
|
||||
|
|
@ -339,41 +411,49 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
}
|
||||
|
||||
refresh_section_count () {
|
||||
refresh_section_count() {
|
||||
this.wrapper.find(".section-count-label:visible").each(function (i) {
|
||||
$(this).html(i + 1);
|
||||
});
|
||||
}
|
||||
setup_tabbing () {
|
||||
var me = this;
|
||||
this.wrapper.on("keydown", function (ev) {
|
||||
|
||||
setup_events() {
|
||||
this.tabs_list.off('click').on('click', '.nav-link', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
$(e.currentTarget).tab('show');
|
||||
});
|
||||
}
|
||||
|
||||
setup_tab_events() {
|
||||
this.wrapper.on("keydown", (ev) => {
|
||||
if (ev.which == 9) {
|
||||
var current = $(ev.target),
|
||||
doctype = current.attr("data-doctype"),
|
||||
fieldname = current.attr("data-fieldname");
|
||||
if (doctype)
|
||||
return me.handle_tab(doctype, fieldname, ev.shiftKey);
|
||||
let current = $(ev.target);
|
||||
let doctype = current.attr("data-doctype");
|
||||
let fieldname = current.attr("data-fieldname");
|
||||
if (doctype) {
|
||||
return this.handle_tab(doctype, fieldname, ev.shiftKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
handle_tab (doctype, fieldname, shift) {
|
||||
var me = this,
|
||||
grid_row = null,
|
||||
|
||||
handle_tab(doctype, fieldname, shift) {
|
||||
let grid_row = null,
|
||||
prev = null,
|
||||
fields = me.fields_list,
|
||||
in_grid = false,
|
||||
fields = this.fields_list,
|
||||
focused = false;
|
||||
|
||||
// in grid
|
||||
if (doctype != me.doctype) {
|
||||
grid_row = me.get_open_grid_row();
|
||||
if (doctype != this.doctype) {
|
||||
grid_row = this.get_open_grid_row();
|
||||
if (!grid_row || !grid_row.layout) {
|
||||
return;
|
||||
}
|
||||
fields = grid_row.layout.fields_list;
|
||||
}
|
||||
|
||||
for (var i = 0, len = fields.length; i < len; i++) {
|
||||
for (let i = 0, len = fields.length; i < len; i++) {
|
||||
if (fields[i].df.fieldname == fieldname) {
|
||||
if (shift) {
|
||||
if (prev) {
|
||||
|
|
@ -384,7 +464,7 @@ frappe.ui.form.Layout = class Layout {
|
|||
break;
|
||||
}
|
||||
if (i < len - 1) {
|
||||
focused = me.focus_on_next_field(i, fields);
|
||||
focused = this.focus_on_next_field(i, fields);
|
||||
}
|
||||
|
||||
if (focused) {
|
||||
|
|
@ -416,10 +496,11 @@ frappe.ui.form.Layout = class Layout {
|
|||
|
||||
return false;
|
||||
}
|
||||
focus_on_next_field (start_idx, fields) {
|
||||
|
||||
focus_on_next_field(start_idx, fields) {
|
||||
// loop to find next eligible fields
|
||||
for (var i = start_idx + 1, len = fields.length; i < len; i++) {
|
||||
var field = fields[i];
|
||||
for (let i = start_idx + 1, len = fields.length; i < len; i++) {
|
||||
let field = fields[i];
|
||||
if (this.is_visible(field)) {
|
||||
if (field.df.fieldtype === "Table") {
|
||||
// open table grid
|
||||
|
|
@ -438,10 +519,15 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
}
|
||||
}
|
||||
is_visible (field) {
|
||||
return field.disp_status === "Write" && (field.$wrapper && field.$wrapper.is(":visible"));
|
||||
|
||||
is_visible(field) {
|
||||
return field.disp_status === "Write" && (field.df && "hidden" in field.df && !field.df.hidden);
|
||||
}
|
||||
set_focus (field) {
|
||||
|
||||
set_focus(field) {
|
||||
if (field.tab) {
|
||||
field.tab.set_active();
|
||||
}
|
||||
// next is table, show the table
|
||||
if (field.df.fieldtype=="Table") {
|
||||
if (!field.grid.grid_rows.length) {
|
||||
|
|
@ -455,18 +541,19 @@ frappe.ui.form.Layout = class Layout {
|
|||
field.$input.focus();
|
||||
}
|
||||
}
|
||||
get_open_grid_row () {
|
||||
|
||||
get_open_grid_row() {
|
||||
return $(".grid-row-open").data("grid_row");
|
||||
}
|
||||
refresh_dependency () {
|
||||
|
||||
refresh_dependency() {
|
||||
// Resolve "depends_on" and show / hide accordingly
|
||||
var me = this;
|
||||
|
||||
// build dependants' dictionary
|
||||
var has_dep = false;
|
||||
let has_dep = false;
|
||||
|
||||
for (var fkey in this.fields_list) {
|
||||
var f = this.fields_list[fkey];
|
||||
for (let fkey in this.fields_list) {
|
||||
let f = this.fields_list[fkey];
|
||||
f.dependencies_clear = true;
|
||||
if (f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) {
|
||||
has_dep = true;
|
||||
|
|
@ -476,8 +563,8 @@ frappe.ui.form.Layout = class Layout {
|
|||
if (!has_dep) return;
|
||||
|
||||
// show / hide based on values
|
||||
for (var i = me.fields_list.length - 1; i >= 0; i--) {
|
||||
var f = me.fields_list[i];
|
||||
for (let i = this.fields_list.length - 1; i >= 0; i--) {
|
||||
let f = this.fields_list[i];
|
||||
f.guardian_has_value = true;
|
||||
if (f.df.depends_on) {
|
||||
// evaluate guardian
|
||||
|
|
@ -509,7 +596,8 @@ frappe.ui.form.Layout = class Layout {
|
|||
|
||||
this.refresh_section_count();
|
||||
}
|
||||
set_dependant_property (condition, fieldname, property) {
|
||||
|
||||
set_dependant_property(condition, fieldname, property) {
|
||||
let set_property = this.evaluate_depends_on_value(condition);
|
||||
let value = set_property ? 1 : 0;
|
||||
let form_obj;
|
||||
|
|
@ -531,19 +619,20 @@ frappe.ui.form.Layout = class Layout {
|
|||
}
|
||||
}
|
||||
}
|
||||
evaluate_depends_on_value (expression) {
|
||||
var out = null;
|
||||
var doc = this.doc;
|
||||
|
||||
evaluate_depends_on_value(expression) {
|
||||
let out = null;
|
||||
let doc = this.doc;
|
||||
|
||||
if (!doc && this.get_values) {
|
||||
var doc = this.get_values(true);
|
||||
doc = this.get_values(true);
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parent = this.frm ? this.frm.doc : this.doc || null;
|
||||
let parent = this.frm ? this.frm.doc : this.doc || null;
|
||||
|
||||
if (typeof (expression) === 'boolean') {
|
||||
out = expression;
|
||||
|
|
@ -575,160 +664,3 @@ frappe.ui.form.Layout = class Layout {
|
|||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
frappe.ui.form.Section = class FormSection {
|
||||
constructor(layout, df) {
|
||||
this.layout = layout;
|
||||
this.df = df || {};
|
||||
this.fields_list = [];
|
||||
this.fields_dict = {};
|
||||
|
||||
this.make();
|
||||
// if (this.frm)
|
||||
// this.section.body.css({"padding":"0px 3%"})
|
||||
this.row = {
|
||||
wrapper: this.wrapper
|
||||
};
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
make() {
|
||||
if (!this.layout.page) {
|
||||
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper);
|
||||
}
|
||||
let make_card = this.layout.card_layout;
|
||||
this.wrapper = $(`<div class="row form-section ${ make_card ? "card-section" : "" }">`)
|
||||
.appendTo(this.layout.page);
|
||||
this.layout.sections.push(this);
|
||||
|
||||
if (this.df) {
|
||||
if (this.df.label) {
|
||||
this.make_head();
|
||||
}
|
||||
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) {
|
||||
this.wrapper.addClass(this.df.cssClass);
|
||||
}
|
||||
if (this.df.hide_border) {
|
||||
this.wrapper.toggleClass("hide-border", true);
|
||||
}
|
||||
}
|
||||
|
||||
// for bc
|
||||
this.body = $('<div class="section-body">').appendTo(this.wrapper);
|
||||
}
|
||||
|
||||
make_head () {
|
||||
this.head = $(`<div class="section-head">
|
||||
${__(this.df.label)}
|
||||
<span class="ml-2 collapse-indicator mb-1">
|
||||
</span>
|
||||
</div>`);
|
||||
this.head.appendTo(this.wrapper);
|
||||
this.indicator = this.head.find('.collapse-indicator');
|
||||
this.indicator.hide();
|
||||
if (this.df.collapsible) {
|
||||
// show / hide based on status
|
||||
this.collapse_link = this.head.on("click", () => {
|
||||
this.collapse();
|
||||
});
|
||||
|
||||
this.indicator.show();
|
||||
}
|
||||
}
|
||||
refresh() {
|
||||
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")) {
|
||||
hide = true;
|
||||
}
|
||||
|
||||
this.wrapper.toggleClass("hide-control", !!hide);
|
||||
}
|
||||
collapse (hide) {
|
||||
// unknown edge case
|
||||
if (!(this.head && this.body)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hide===undefined) {
|
||||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
this.body.toggleClass("hide", hide);
|
||||
this.head.toggleClass("collapsed", hide);
|
||||
|
||||
let indicator_icon = hide ? 'down' : 'up-line';
|
||||
|
||||
this.indicator & this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));
|
||||
|
||||
// refresh signature fields
|
||||
this.fields_list.forEach((f) => {
|
||||
if (f.df.fieldtype == 'Signature') {
|
||||
f.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
is_collapsed() {
|
||||
return this.body.hasClass('hide');
|
||||
}
|
||||
|
||||
has_missing_mandatory () {
|
||||
var missing_mandatory = false;
|
||||
for (var j = 0, l = this.fields_list.length; j < l; j++) {
|
||||
var section_df = this.fields_list[j].df;
|
||||
if (section_df.reqd && this.layout.doc[section_df.fieldname] == null) {
|
||||
missing_mandatory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return missing_mandatory;
|
||||
}
|
||||
};
|
||||
|
||||
frappe.ui.form.Column = class FormColumn {
|
||||
constructor(section, df) {
|
||||
if (!df) df = {};
|
||||
|
||||
this.df = df;
|
||||
this.section = section;
|
||||
this.make();
|
||||
this.resize_all_columns();
|
||||
}
|
||||
make () {
|
||||
this.wrapper = $('<div class="form-column">\
|
||||
<form>\
|
||||
</form>\
|
||||
</div>').appendTo(this.section.body)
|
||||
.find("form")
|
||||
.on("submit", function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (this.df.label) {
|
||||
$('<label class="control-label">' + __(this.df.label)
|
||||
+ '</label>').appendTo(this.wrapper);
|
||||
}
|
||||
}
|
||||
resize_all_columns () {
|
||||
// distribute all columns equally
|
||||
var colspan = cint(12 / this.section.wrapper.find(".form-column").length);
|
||||
|
||||
this.section.wrapper.find(".form-column").removeClass()
|
||||
.addClass("form-column")
|
||||
.addClass("col-sm-" + colspan);
|
||||
|
||||
}
|
||||
refresh () {
|
||||
this.section.refresh();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
146
frappe/public/js/frappe/form/section.js
Normal file
146
frappe/public/js/frappe/form/section.js
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
export default class Section {
|
||||
constructor(parent, df, card_layout) {
|
||||
this.card_layout = card_layout;
|
||||
this.parent = parent;
|
||||
this.df = df || {};
|
||||
this.fields_list = [];
|
||||
this.fields_dict = {};
|
||||
|
||||
this.make();
|
||||
|
||||
if (this.df.label && this.df.collapsible && localStorage.getItem(df.css_class + '-closed')) {
|
||||
this.collapse();
|
||||
}
|
||||
|
||||
this.row = {
|
||||
wrapper: this.wrapper
|
||||
};
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
make() {
|
||||
let make_card = this.card_layout;
|
||||
this.wrapper = $(`<div class="row
|
||||
${this.df.is_dashboard_section ? "form-dashboard-section" : "form-section"}
|
||||
${ make_card ? "card-section" : "" }">
|
||||
`).appendTo(this.parent);
|
||||
|
||||
if (this.df) {
|
||||
if (this.df.label) {
|
||||
this.make_head();
|
||||
}
|
||||
if (this.df.description) {
|
||||
this.description_wrapper = $(
|
||||
`<div class="col-sm-12 form-section-description">
|
||||
${__(this.df.description)}
|
||||
</div>`
|
||||
);
|
||||
|
||||
this.wrapper.append(this.description_wrapper);
|
||||
}
|
||||
if (this.df.css_class) {
|
||||
this.wrapper.addClass(this.df.css_class);
|
||||
}
|
||||
if (this.df.hide_border) {
|
||||
this.wrapper.toggleClass("hide-border", true);
|
||||
}
|
||||
}
|
||||
|
||||
this.body = $('<div class="section-body">').appendTo(this.wrapper);
|
||||
|
||||
if (this.df.body_html) {
|
||||
this.body.append(this.df.body_html);
|
||||
}
|
||||
}
|
||||
|
||||
make_head() {
|
||||
this.head = $(`
|
||||
<div class="section-head">
|
||||
${__(this.df.label)}
|
||||
<span class="ml-2 collapse-indicator mb-1"></span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
this.head.appendTo(this.wrapper);
|
||||
this.indicator = this.head.find('.collapse-indicator');
|
||||
this.indicator.hide();
|
||||
|
||||
if (this.df.collapsible) {
|
||||
// show / hide based on status
|
||||
this.collapse_link = this.head.on("click", () => {
|
||||
this.collapse();
|
||||
});
|
||||
this.set_icon();
|
||||
this.indicator.show();
|
||||
}
|
||||
}
|
||||
|
||||
refresh(hide) {
|
||||
if (!this.df) return;
|
||||
// hide if explicitly hidden
|
||||
hide = hide || this.df.hidden || this.df.hidden_due_to_dependency;
|
||||
this.wrapper.toggleClass("hide-control", !!hide);
|
||||
}
|
||||
|
||||
collapse(hide) {
|
||||
// unknown edge case
|
||||
if (!(this.head && this.body)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hide === undefined) {
|
||||
hide = !this.body.hasClass("hide");
|
||||
}
|
||||
|
||||
this.body.toggleClass("hide", hide);
|
||||
this.head && this.head.toggleClass("collapsed", hide);
|
||||
|
||||
this.set_icon(hide);
|
||||
|
||||
// refresh signature fields
|
||||
this.fields_list.forEach((f) => {
|
||||
if (f.df.fieldtype == 'Signature') {
|
||||
f.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
// save state for next reload ('' is falsy)
|
||||
if (this.df.css_class)
|
||||
localStorage.setItem(this.df.css_class + '-closed', hide ? '1' : '');
|
||||
}
|
||||
|
||||
set_icon(hide) {
|
||||
let indicator_icon = hide ? 'down' : 'up-line';
|
||||
this.indicator && this.indicator.html(frappe.utils.icon(indicator_icon, 'sm', 'mb-1'));
|
||||
}
|
||||
|
||||
is_collapsed() {
|
||||
return this.body.hasClass('hide');
|
||||
}
|
||||
|
||||
has_missing_mandatory () {
|
||||
let missing_mandatory = false;
|
||||
for (let j = 0, l = this.fields_list.length; j < l; j++) {
|
||||
const section_df = this.fields_list[j].df;
|
||||
if (section_df.reqd && this.layout.doc[section_df.fieldname] == null) {
|
||||
missing_mandatory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return missing_mandatory;
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.on_section_toggle(false);
|
||||
}
|
||||
|
||||
show() {
|
||||
this.on_section_toggle(true);
|
||||
}
|
||||
|
||||
on_section_toggle(show) {
|
||||
this.wrapper.toggleClass("hide-control", !show);
|
||||
// this.on_section_toggle && this.on_section_toggle(show);
|
||||
}
|
||||
}
|
||||
75
frappe/public/js/frappe/form/tab.js
Normal file
75
frappe/public/js/frappe/form/tab.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
export default class Tab {
|
||||
constructor(parent, df, frm, tabs_list, tabs_content) {
|
||||
this.parent = parent;
|
||||
this.df = df || {};
|
||||
this.frm = frm;
|
||||
this.doctype = 'User';
|
||||
this.label = this.df && this.df.label;
|
||||
this.tabs_list = tabs_list;
|
||||
this.tabs_content = tabs_content;
|
||||
this.fields_list = [];
|
||||
this.fields_dict = {};
|
||||
this.make();
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
make() {
|
||||
const id = `${frappe.scrub(this.doctype, '-')}-${this.df.fieldname}`;
|
||||
this.parent = $(`
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${this.df.active ? "active": ""}" id="${id}-tab"
|
||||
data-toggle="tab"
|
||||
href="#${id}"
|
||||
role="tab"
|
||||
aria-controls="${this.label}">
|
||||
${__(this.label)}
|
||||
</a>
|
||||
</li>
|
||||
`).appendTo(this.tabs_list);
|
||||
|
||||
this.wrapper = $(`<div class="tab-pane fade show ${this.df.active ? "active": ""}"
|
||||
id="${id}" role="tabpanel" aria-labelledby="${id}-tab">`).appendTo(this.tabs_content);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
if (!this.df) return;
|
||||
|
||||
// hide if explicitly hidden
|
||||
let hide = this.df.hidden || this.df.hidden_due_to_dependency;
|
||||
if (!hide && this.frm && !this.frm.get_perm(this.df.permlevel || 0, "read")) {
|
||||
hide = true;
|
||||
}
|
||||
|
||||
hide && this.toggle(false);
|
||||
}
|
||||
|
||||
toggle(show) {
|
||||
this.parent.toggleClass('hide', !show);
|
||||
this.wrapper.toggleClass('hide', !show);
|
||||
this.parent.toggleClass('show', show);
|
||||
this.wrapper.toggleClass('show', show);
|
||||
this.hidden = !show;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.parent.show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.parent.hide();
|
||||
}
|
||||
|
||||
set_active() {
|
||||
this.parent.find('.nav-link').tab('show');
|
||||
this.wrapper.addClass('show');
|
||||
}
|
||||
|
||||
is_active() {
|
||||
return this.wrapper.hasClass('active');
|
||||
}
|
||||
|
||||
is_hidden() {
|
||||
this.wrapper.hasClass('hide')
|
||||
&& this.parent.hasClass('hide');
|
||||
}
|
||||
}
|
||||
|
|
@ -545,7 +545,7 @@ frappe.ui.form.Toolbar = class Toolbar {
|
|||
|
||||
show_jump_to_field_dialog() {
|
||||
let visible_fields_filter = f =>
|
||||
!['Section Break', 'Column Break'].includes(f.df.fieldtype)
|
||||
!['Section Break', 'Column Break', 'Tab Break'].includes(f.df.fieldtype)
|
||||
&& !f.df.hidden
|
||||
&& f.disp_status !== 'None';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
frappe.provide('frappe.model');
|
||||
|
||||
$.extend(frappe.model, {
|
||||
no_value_type: ['Section Break', 'Column Break', 'HTML', 'Table', 'Table MultiSelect',
|
||||
no_value_type: ['Section Break', 'Column Break', 'Tab Break', 'HTML', 'Table', 'Table MultiSelect',
|
||||
'Button', 'Image', 'Fold', 'Heading'],
|
||||
|
||||
layout_fields: ['Section Break', 'Column Break', 'Fold'],
|
||||
layout_fields: ['Section Break', 'Column Break', 'Tab Break', 'Fold'],
|
||||
|
||||
std_fields_list: ['name', 'owner', 'creation', 'modified', 'modified_by',
|
||||
'_user_tags', '_comments', '_assign', '_liked_by', 'docstatus',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ frappe.provide('frappe.ui');
|
|||
frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
this.first_button = false;
|
||||
this.dirty = false;
|
||||
$.each(this.fields || [], function(i, f) {
|
||||
if(!f.fieldname && f.label) {
|
||||
|
|
@ -16,6 +15,7 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
this.set_values(this.values);
|
||||
}
|
||||
}
|
||||
|
||||
make() {
|
||||
var me = this;
|
||||
if(this.fields) {
|
||||
|
|
@ -63,6 +63,7 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
catch_enter_as_submit() {
|
||||
var me = this;
|
||||
$(this.body).find('input[type="text"], input[type="password"], select').keypress(function(e) {
|
||||
|
|
@ -74,13 +75,16 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
get_input(fieldname) {
|
||||
var field = this.fields_dict[fieldname];
|
||||
return $(field.txt ? field.txt : field.input);
|
||||
}
|
||||
|
||||
get_field(fieldname) {
|
||||
return this.fields_dict[fieldname];
|
||||
}
|
||||
|
||||
get_values(ignore_errors) {
|
||||
var ret = {};
|
||||
var errors = [];
|
||||
|
|
@ -113,14 +117,16 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
get_value(key) {
|
||||
var f = this.fields_dict[key];
|
||||
return f && (f.get_value ? f.get_value() : null);
|
||||
}
|
||||
set_value(key, val){
|
||||
|
||||
set_value(key, val) {
|
||||
return new Promise(resolve => {
|
||||
var f = this.fields_dict[key];
|
||||
if(f) {
|
||||
if (f) {
|
||||
f.set_value(val).then(() => {
|
||||
f.set_input(val);
|
||||
this.refresh_dependency();
|
||||
|
|
@ -131,9 +137,11 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
set_input(key, val) {
|
||||
return this.set_value(key, val);
|
||||
}
|
||||
|
||||
set_values(dict) {
|
||||
let promises = [];
|
||||
for(var key in dict) {
|
||||
|
|
@ -144,6 +152,7 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
clear() {
|
||||
for(var key in this.fields_dict) {
|
||||
var f = this.fields_dict[key];
|
||||
|
|
@ -152,8 +161,9 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_df_property (fieldname, prop, value) {
|
||||
const field = this.get_field(fieldname);
|
||||
const field = this.get_field(fieldname);
|
||||
field.df[prop] = value;
|
||||
field.refresh();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@
|
|||
@extend .frappe-card;
|
||||
}
|
||||
|
||||
.form-dashboard {
|
||||
.form-dashboard-section {
|
||||
.section-body:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.form-dashboard-section .section-body {
|
||||
.section-body {
|
||||
display: block;
|
||||
padding-left: var(--padding-md);
|
||||
padding-right: var(--padding-md);
|
||||
|
|
@ -303,6 +303,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
.form-tabs-list {
|
||||
margin-bottom: var(--margin-lg);
|
||||
|
||||
.form-tabs {
|
||||
.nav-item {
|
||||
.nav-link {
|
||||
padding-bottom: var(--padding-md);
|
||||
color: var(--gray-700);
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-right: var(--margin-xl);
|
||||
|
||||
&.active {
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid var(--primary);
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-area {
|
||||
padding-top: var(--padding-md);
|
||||
padding-bottom: var(--padding-md);
|
||||
|
|
@ -356,7 +378,4 @@
|
|||
.form-column:not(:first-child) {
|
||||
padding-top: var(--padding-md);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue