@@ -9,19 +9,25 @@ export default class Column { | |||
} | |||
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") | |||
.on("submit", function () { | |||
return false; | |||
}); | |||
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 | |||
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("col-sm-" + colspan); | |||
@@ -2,35 +2,22 @@ | |||
// MIT License. See license.txt | |||
import Section from "./section.js"; | |||
import Tab from "./tab.js"; | |||
frappe.ui.form.Dashboard = class FormDashboard { | |||
constructor(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(); | |||
} | |||
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() { | |||
this.progress_area = this.make_section({ | |||
css_class: 'progress-area', | |||
hidden: 1, | |||
is_dashboard_section: 1, | |||
}, this.overview_tab); | |||
}); | |||
this.heatmap_area = this.make_section({ | |||
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 class="text-muted small heatmap-message hidden"></div> | |||
` | |||
}, this.overview_tab); | |||
}); | |||
this.chart_area = this.make_section({ | |||
label: __("Graph"), | |||
css_class: 'form-graph', | |||
hidden: 1, | |||
is_dashboard_section: 1 | |||
}, this.overview_tab); | |||
}); | |||
this.stats_area_row = $(`<div class="row"></div>`); | |||
this.stats_area = this.make_section({ | |||
@@ -57,7 +44,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||
hidden: 1, | |||
is_dashboard_section: 1, | |||
body_html: this.stats_area_row | |||
}, this.overview_tab); | |||
}); | |||
this.transactions_area = $(`<div class="transactions"></div`); | |||
@@ -67,20 +54,14 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||
hidden: 1, | |||
is_dashboard_section: 1, | |||
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() { | |||
// this.hide(); | |||
// clear progress | |||
this.progress_area.body.empty(); | |||
this.progress_area.hide(); | |||
@@ -98,8 +79,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||
// 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 = { | |||
label, | |||
css_class, | |||
@@ -108,7 +88,7 @@ frappe.ui.form.Dashboard = class FormDashboard { | |||
make_card: true, | |||
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) { | |||
@@ -133,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! | |||
@@ -146,9 +146,9 @@ frappe.ui.form.Form = class FrappeForm { | |||
doctype_layout: this.doctype_layout, | |||
frm: this, | |||
with_dashboard: true, | |||
card_layout: true, | |||
tabbed_layout: true, | |||
card_layout: true | |||
}); | |||
this.layout.make(); | |||
this.fields_dict = this.layout.fields_dict; | |||
@@ -156,7 +156,7 @@ frappe.ui.form.Form = class FrappeForm { | |||
this.dashboard = new frappe.ui.form.Dashboard({ | |||
frm: this, | |||
parent: this.layout.wrapper, | |||
tab: this.layout.tabs.length ? this.layout.tabs[0] : null | |||
}); | |||
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.message = $('<div class="form-message hidden"></div>').appendTo(this.wrapper); | |||
this.page = $('<div class="form-page"></div>').appendTo(this.wrapper); | |||
this.tabbed_layout && this.setup_tabbed_layout(); | |||
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); | |||
$(` | |||
<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(); | |||
} | |||
@@ -114,16 +117,16 @@ frappe.ui.form.Layout = class Layout { | |||
this.section = 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 => { | |||
@@ -154,10 +157,8 @@ frappe.ui.form.Layout = class Layout { | |||
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) { | |||
@@ -190,7 +191,7 @@ frappe.ui.form.Layout = class Layout { | |||
this.section.fields_list.push(fieldobj); | |||
this.section.fields_dict[df.fieldname] = fieldobj; | |||
fieldobj.section = this.section; | |||
fieldobj.tab = this.tab; | |||
fieldobj.tab = this.current_tab; | |||
} | |||
init_field(df, render=false) { | |||
@@ -239,7 +240,7 @@ frappe.ui.form.Layout = class Layout { | |||
} | |||
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 | |||
if (df) { | |||
@@ -258,14 +259,12 @@ frappe.ui.form.Layout = class Layout { | |||
} | |||
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) { | |||
@@ -421,14 +420,15 @@ frappe.ui.form.Layout = class Layout { | |||
}); | |||
} | |||
setup_tabbing() { | |||
setup_tab_events() { | |||
this.wrapper.on("keydown", (ev) => { | |||
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); | |||
} | |||
} | |||
}); | |||
} | |||
@@ -1,10 +1,7 @@ | |||
// import '../class'; | |||
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.fields_list = []; | |||
this.fields_dict = {}; | |||
@@ -23,18 +20,11 @@ export default class Section { | |||
} | |||
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.df.is_dashboard_section ? "form-dashboard-section" : "form-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.label) { | |||
@@ -86,17 +76,11 @@ export default class Section { | |||
} | |||
} | |||
refresh() { | |||
refresh(hide) { | |||
if (!this.df) return; | |||
// 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.tab && this.tab.refresh(); | |||
} | |||
collapse(hide) { | |||
@@ -136,9 +120,9 @@ export default class Section { | |||
} | |||
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) { | |||
missing_mandatory = true; | |||
break; | |||
@@ -148,11 +132,15 @@ export default class Section { | |||
} | |||
hide() { | |||
this.wrapper.toggleClass("hide-control", true); | |||
this.on_section_toggle(false); | |||
} | |||
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 { | |||
constructor(layout, df) { | |||
this.layout = layout; | |||
constructor(parent, df, frm, tabs_list, tabs_content) { | |||
this.parent = parent; | |||
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_dict = {}; | |||
this.make(); | |||
@@ -10,28 +14,21 @@ export default class Tab { | |||
} | |||
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": ""}" | |||
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() { | |||
@@ -39,15 +36,15 @@ export default class Tab { | |||
// 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")) { | |||
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.parent.toggleClass('hide', !show); | |||
this.wrapper.toggleClass('hide', !show); | |||
this.parent.toggleClass('show', show); | |||
this.wrapper.toggleClass('show', show); | |||