@@ -9,19 +9,25 @@ export default class Column { | |||||
} | } | ||||
make() { | make() { | ||||
this.wrapper = $(`<div class="form-column"> | |||||
<form> | |||||
</form> | |||||
</div>`).appendTo(this.section.body) | |||||
this.wrapper = $(` | |||||
<div class="form-column"> | |||||
<form> | |||||
</form> | |||||
</div> | |||||
`) | |||||
.appendTo(this.section.body) | |||||
.find("form") | .find("form") | ||||
.on("submit", function () { | .on("submit", function () { | ||||
return false; | return false; | ||||
}); | }); | ||||
if (this.df.label) { | if (this.df.label) { | ||||
$(`<label class="control-label"> | |||||
${__(this.df.label)} | |||||
</label>`).appendTo(this.wrapper); | |||||
$(` | |||||
<label class="control-label"> | |||||
${__(this.df.label)} | |||||
</label> | |||||
`) | |||||
.appendTo(this.wrapper); | |||||
} | } | ||||
} | } | ||||
@@ -29,7 +35,9 @@ export default class Column { | |||||
// distribute all columns equally | // distribute all columns equally | ||||
let colspan = cint(12 / this.section.wrapper.find(".form-column").length); | let colspan = cint(12 / this.section.wrapper.find(".form-column").length); | ||||
this.section.wrapper.find(".form-column").removeClass() | |||||
this.section.wrapper | |||||
.find(".form-column") | |||||
.removeClass() | |||||
.addClass("form-column") | .addClass("form-column") | ||||
.addClass("col-sm-" + colspan); | .addClass("col-sm-" + colspan); | ||||
@@ -2,35 +2,22 @@ | |||||
// MIT License. See license.txt | // MIT License. See license.txt | ||||
import Section from "./section.js"; | import Section from "./section.js"; | ||||
import Tab from "./tab.js"; | |||||
frappe.ui.form.Dashboard = class FormDashboard { | frappe.ui.form.Dashboard = class FormDashboard { | ||||
constructor(opts) { | constructor(opts) { | ||||
$.extend(this, opts); | $.extend(this, opts); | ||||
this.setup_dashboard_tabs(); | |||||
let parent = this.tab ? this.tab.wrapper : this.frm.layout.wrapper; | |||||
this.parent = $('<div class="form-dashboard">'); | |||||
parent.prepend(this.parent); | |||||
this.setup_dashboard_sections(); | this.setup_dashboard_sections(); | ||||
} | } | ||||
setup_dashboard_tabs() { | |||||
this.overview_tab = new Tab(this.frm.layout, { | |||||
label: __("Overview"), | |||||
hidden: 1, | |||||
fieldname: 'dashboard-overview' | |||||
}); | |||||
this.connections_tab = new Tab(this.frm.layout, { | |||||
label: __("Connections"), | |||||
hidden: 1, | |||||
fieldname: 'dashboard-connection' | |||||
}); | |||||
} | |||||
setup_dashboard_sections() { | setup_dashboard_sections() { | ||||
this.progress_area = this.make_section({ | this.progress_area = this.make_section({ | ||||
css_class: 'progress-area', | css_class: 'progress-area', | ||||
hidden: 1, | hidden: 1, | ||||
is_dashboard_section: 1, | is_dashboard_section: 1, | ||||
}, this.overview_tab); | |||||
}); | |||||
this.heatmap_area = this.make_section({ | this.heatmap_area = this.make_section({ | ||||
label: __("Overview"), | label: __("Overview"), | ||||
@@ -41,14 +28,14 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||||
<div id="heatmap-${frappe.model.scrub(this.frm.doctype)}" class="heatmap"></div> | <div id="heatmap-${frappe.model.scrub(this.frm.doctype)}" class="heatmap"></div> | ||||
<div class="text-muted small heatmap-message hidden"></div> | <div class="text-muted small heatmap-message hidden"></div> | ||||
` | ` | ||||
}, this.overview_tab); | |||||
}); | |||||
this.chart_area = this.make_section({ | this.chart_area = this.make_section({ | ||||
label: __("Graph"), | label: __("Graph"), | ||||
css_class: 'form-graph', | css_class: 'form-graph', | ||||
hidden: 1, | hidden: 1, | ||||
is_dashboard_section: 1 | is_dashboard_section: 1 | ||||
}, this.overview_tab); | |||||
}); | |||||
this.stats_area_row = $(`<div class="row"></div>`); | this.stats_area_row = $(`<div class="row"></div>`); | ||||
this.stats_area = this.make_section({ | this.stats_area = this.make_section({ | ||||
@@ -57,7 +44,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||||
hidden: 1, | hidden: 1, | ||||
is_dashboard_section: 1, | is_dashboard_section: 1, | ||||
body_html: this.stats_area_row | body_html: this.stats_area_row | ||||
}, this.overview_tab); | |||||
}); | |||||
this.transactions_area = $(`<div class="transactions"></div`); | this.transactions_area = $(`<div class="transactions"></div`); | ||||
@@ -67,20 +54,14 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||||
hidden: 1, | hidden: 1, | ||||
is_dashboard_section: 1, | is_dashboard_section: 1, | ||||
body_html: this.transactions_area | body_html: this.transactions_area | ||||
}, this.connections_tab); | |||||
}); | |||||
} | } | ||||
make_section(df, tab) { | |||||
return new Section( | |||||
this.frm.layout, | |||||
df, | |||||
tab, | |||||
); | |||||
make_section(df) { | |||||
return new Section(this.parent, df); | |||||
} | } | ||||
reset() { | reset() { | ||||
// this.hide(); | |||||
// clear progress | // clear progress | ||||
this.progress_area.body.empty(); | this.progress_area.body.empty(); | ||||
this.progress_area.hide(); | this.progress_area.hide(); | ||||
@@ -98,8 +79,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||||
// this.hide(); | // this.hide(); | ||||
} | } | ||||
add_section(body_html, label=null, css_class="custom", hidden=false, tab=null) { | |||||
if (!tab) tab = this.overview_tab; | |||||
add_section(body_html, label=null, css_class="custom", hidden=false) { | |||||
let options = { | let options = { | ||||
label, | label, | ||||
css_class, | css_class, | ||||
@@ -108,7 +88,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||||
make_card: true, | make_card: true, | ||||
is_dashboard_section: 1 | is_dashboard_section: 1 | ||||
}; | }; | ||||
return new Section(this.frm.layout, options, tab).body; | |||||
return new Section(this.frm.layout, options).body; | |||||
} | } | ||||
add_progress(title, percent, message) { | add_progress(title, percent, message) { | ||||
@@ -133,8 +133,8 @@ frappe.ui.form.Form = class FrappeForm { | |||||
} | } | ||||
setup_std_layout() { | 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 | // only tray | ||||
this.meta.section_style='Simple'; // always simple! | this.meta.section_style='Simple'; // always simple! | ||||
@@ -146,9 +146,9 @@ frappe.ui.form.Form = class FrappeForm { | |||||
doctype_layout: this.doctype_layout, | doctype_layout: this.doctype_layout, | ||||
frm: this, | frm: this, | ||||
with_dashboard: true, | with_dashboard: true, | ||||
card_layout: true, | |||||
tabbed_layout: true, | |||||
card_layout: true | |||||
}); | }); | ||||
this.layout.make(); | this.layout.make(); | ||||
this.fields_dict = this.layout.fields_dict; | this.fields_dict = this.layout.fields_dict; | ||||
@@ -156,7 +156,7 @@ frappe.ui.form.Form = class FrappeForm { | |||||
this.dashboard = new frappe.ui.form.Dashboard({ | this.dashboard = new frappe.ui.form.Dashboard({ | ||||
frm: this, | frm: this, | ||||
parent: this.layout.wrapper, | |||||
tab: this.layout.tabs.length ? this.layout.tabs[0] : null | |||||
}); | }); | ||||
this.tour = new frappe.ui.form.FormTour({ | this.tour = new frappe.ui.form.FormTour({ | ||||
@@ -20,25 +20,28 @@ frappe.ui.form.Layout = class Layout { | |||||
} | } | ||||
this.wrapper = $('<div class="form-layout">').appendTo(this.parent); | this.wrapper = $('<div class="form-layout">').appendTo(this.parent); | ||||
this.message = $('<div class="form-message hidden"></div>').appendTo(this.wrapper); | this.message = $('<div class="form-message hidden"></div>').appendTo(this.wrapper); | ||||
this.page = $('<div class="form-page"></div>').appendTo(this.wrapper); | this.page = $('<div class="form-page"></div>').appendTo(this.wrapper); | ||||
this.tabbed_layout && this.setup_tabbed_layout(); | |||||
if (!this.fields) { | if (!this.fields) { | ||||
this.fields = this.get_doctype_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(); | this.render(); | ||||
} | } | ||||
setup_tabbed_layout() { | setup_tabbed_layout() { | ||||
$(`<div class="form-tabs-list"> | |||||
<ul class="nav form-tabs" id="form-tabs" role="tablist"></ul> | |||||
</div>`).appendTo(this.page); | |||||
$(` | |||||
<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_list = this.page.find('.form-tabs'); | ||||
this.tabs_content = $(`<div class="form-tab-content tab-content"></div>`).appendTo(this.page); | this.tabs_content = $(`<div class="form-tab-content tab-content"></div>`).appendTo(this.page); | ||||
this.setup_events(); | this.setup_events(); | ||||
} | } | ||||
@@ -114,16 +117,16 @@ frappe.ui.form.Layout = class Layout { | |||||
this.section = null; | this.section = null; | ||||
this.column = null; | this.column = null; | ||||
// if (this.with_dashboard) { | |||||
// this.setup_dashboard_section(); | |||||
// } | |||||
if (this.tabbed_layout && this.no_opening_tab()) { | |||||
this.make_tab({label: __('Details'), fieldname: 'details'}); | |||||
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'}; | |||||
let first_tab = this.fields[1].fieldtype === "Tab Break" ? this.fields[1] : null; | |||||
if (!first_tab) { | |||||
this.fields.splice(1, 0, default_tab); | |||||
} | |||||
} | } | ||||
fields.forEach(df => { | fields.forEach(df => { | ||||
@@ -154,10 +157,8 @@ frappe.ui.form.Layout = class Layout { | |||||
return (this.fields[1] && this.fields[1].fieldtype != "Tab Break") || !this.fields.length; | return (this.fields[1] && this.fields[1].fieldtype != "Tab Break") || !this.fields.length; | ||||
} | } | ||||
setup_dashboard_section() { | |||||
if (this.no_opening_section()) { | |||||
this.fields.unshift({fieldtype: 'Section Break'}); | |||||
} | |||||
is_tabbed_layout() { | |||||
return this.fields.find(f => f.fieldtype === "Tab Break"); | |||||
} | } | ||||
replace_field(fieldname, df, render) { | replace_field(fieldname, df, render) { | ||||
@@ -190,7 +191,7 @@ frappe.ui.form.Layout = class Layout { | |||||
this.section.fields_list.push(fieldobj); | this.section.fields_list.push(fieldobj); | ||||
this.section.fields_dict[df.fieldname] = fieldobj; | this.section.fields_dict[df.fieldname] = fieldobj; | ||||
fieldobj.section = this.section; | fieldobj.section = this.section; | ||||
fieldobj.tab = this.tab; | |||||
fieldobj.tab = this.current_tab; | |||||
} | } | ||||
init_field(df, render=false) { | init_field(df, render=false) { | ||||
@@ -239,7 +240,7 @@ frappe.ui.form.Layout = class Layout { | |||||
} | } | ||||
make_section(df) { | make_section(df) { | ||||
this.section = new Section(this, df, this.tab || null); | |||||
this.section = new Section(this, df, this.current_tab || null); | |||||
// append to layout fields | // append to layout fields | ||||
if (df) { | if (df) { | ||||
@@ -258,14 +259,12 @@ frappe.ui.form.Layout = class Layout { | |||||
} | } | ||||
make_tab(df) { | make_tab(df) { | ||||
this.tab = new Tab(this, df); | |||||
if (df) { | |||||
this.fields_dict[df.fieldname] = this.tab; | |||||
this.fields_list.push(this.tab); | |||||
} | |||||
return this.tab; | |||||
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) { | refresh(doc) { | ||||
@@ -421,14 +420,15 @@ frappe.ui.form.Layout = class Layout { | |||||
}); | }); | ||||
} | } | ||||
setup_tabbing() { | |||||
setup_tab_events() { | |||||
this.wrapper.on("keydown", (ev) => { | this.wrapper.on("keydown", (ev) => { | ||||
if (ev.which == 9) { | if (ev.which == 9) { | ||||
let current = $(ev.target), | |||||
doctype = current.attr("data-doctype"), | |||||
fieldname = current.attr("data-fieldname"); | |||||
if (doctype) | |||||
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); | return this.handle_tab(doctype, fieldname, ev.shiftKey); | ||||
} | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
@@ -1,10 +1,7 @@ | |||||
// import '../class'; | |||||
export default class Section { | export default class Section { | ||||
constructor(layout, df, tab) { | |||||
this.layout = layout; | |||||
this.tab = tab; | |||||
this.parent = this.tab && this.tab.wrapper || null; | |||||
constructor(parent, df) { | |||||
this.card_layout = true; | |||||
this.parent = parent; | |||||
this.df = df || {}; | this.df = df || {}; | ||||
this.fields_list = []; | this.fields_list = []; | ||||
this.fields_dict = {}; | this.fields_dict = {}; | ||||
@@ -23,18 +20,11 @@ export default class Section { | |||||
} | } | ||||
make() { | make() { | ||||
if (!this.layout.page) { | |||||
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper); | |||||
} | |||||
let make_card = this.layout.card_layout; | |||||
let make_card = this.card_layout; | |||||
this.wrapper = $(`<div class="row | this.wrapper = $(`<div class="row | ||||
${this.df.is_dashboard_section ? "form-dashboard-section" : "form-section"} | ${this.df.is_dashboard_section ? "form-dashboard-section" : "form-section"} | ||||
${ make_card ? "card-section" : "" }"> | ${ make_card ? "card-section" : "" }"> | ||||
`).appendTo(this.parent || this.layout.page); | |||||
this.layout.sections.push(this); | |||||
`).appendTo(this.parent); | |||||
if (this.df) { | if (this.df) { | ||||
if (this.df.label) { | if (this.df.label) { | ||||
@@ -86,17 +76,11 @@ export default class Section { | |||||
} | } | ||||
} | } | ||||
refresh() { | |||||
refresh(hide) { | |||||
if (!this.df) return; | if (!this.df) return; | ||||
// hide if explicitly hidden | // hide if explicitly hidden | ||||
let hide = this.df.hidden || this.df.hidden_due_to_dependency; | |||||
if (!hide && this.layout && this.layout.frm && !this.layout.frm.get_perm(this.df.permlevel || 0, "read")) { | |||||
hide = true; | |||||
} | |||||
hide = hide || this.df.hidden || this.df.hidden_due_to_dependency; | |||||
this.wrapper.toggleClass("hide-control", !!hide); | this.wrapper.toggleClass("hide-control", !!hide); | ||||
// this.tab && this.tab.refresh(); | |||||
} | } | ||||
collapse(hide) { | collapse(hide) { | ||||
@@ -136,9 +120,9 @@ export default class Section { | |||||
} | } | ||||
has_missing_mandatory () { | 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; | |||||
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) { | if (section_df.reqd && this.layout.doc[section_df.fieldname] == null) { | ||||
missing_mandatory = true; | missing_mandatory = true; | ||||
break; | break; | ||||
@@ -148,11 +132,15 @@ export default class Section { | |||||
} | } | ||||
hide() { | hide() { | ||||
this.wrapper.toggleClass("hide-control", true); | |||||
this.on_section_toggle(false); | |||||
} | } | ||||
show() { | show() { | ||||
this.wrapper.toggleClass("hide-control", false); | |||||
this.tab && this.tab.toggle(true); | |||||
this.on_section_toggle(true); | |||||
} | |||||
on_section_toggle(show) { | |||||
this.wrapper.toggleClass("hide-control", !show); | |||||
this.on_section_toggle && this.on_section_toggle(show); | |||||
} | } | ||||
} | } |
@@ -1,8 +1,12 @@ | |||||
export default class Tab { | export default class Tab { | ||||
constructor(layout, df) { | |||||
this.layout = layout; | |||||
constructor(parent, df, frm, tabs_list, tabs_content) { | |||||
this.parent = parent; | |||||
this.df = df || {}; | this.df = df || {}; | ||||
this.label = this.df && this.df.label || 'Details'; | |||||
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_list = []; | ||||
this.fields_dict = {}; | this.fields_dict = {}; | ||||
this.make(); | this.make(); | ||||
@@ -10,28 +14,21 @@ export default class Tab { | |||||
} | } | ||||
make() { | make() { | ||||
if (!this.layout.page) { | |||||
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper); | |||||
} | |||||
const id = `${frappe.scrub(this.layout.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="home" aria-selected="true"> | |||||
${__(this.label)} | |||||
</a> | |||||
</li>`).appendTo(this.layout.tabs_list); | |||||
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": ""}" | this.wrapper = $(`<div class="tab-pane fade show ${this.df.active ? "active": ""}" | ||||
id="${id}" role="tabpanel" aria-labelledby="${id}-tab"> | |||||
`).appendTo(this.layout.tabs_content); | |||||
this.layout.tabs.push(this); | |||||
} | |||||
set_content() { | |||||
id="${id}" role="tabpanel" aria-labelledby="${id}-tab">`).appendTo(this.tabs_content); | |||||
} | } | ||||
refresh() { | refresh() { | ||||
@@ -39,15 +36,15 @@ export default class Tab { | |||||
// hide if explicitly hidden | // hide if explicitly hidden | ||||
let hide = this.df.hidden || this.df.hidden_due_to_dependency; | let hide = this.df.hidden || this.df.hidden_due_to_dependency; | ||||
if (!hide && this.layout && this.layout.frm && !this.layout.frm.get_perm(this.df.permlevel || 0, "read")) { | |||||
if (!hide && this.frm && !this.frm.get_perm(this.df.permlevel || 0, "read")) { | |||||
hide = true; | hide = true; | ||||
} | } | ||||
hide && this.toggle(false); | hide && this.toggle(false); | ||||
} | } | ||||
toggle(show) { | toggle(show) { | ||||
this.parent.toggleClass('hide', !show); | |||||
this.parent.toggleClass('hide', !show); | |||||
this.wrapper.toggleClass('hide', !show); | this.wrapper.toggleClass('hide', !show); | ||||
this.parent.toggleClass('show', show); | this.parent.toggleClass('show', show); | ||||
this.wrapper.toggleClass('show', show); | this.wrapper.toggleClass('show', show); | ||||