2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 15:50:56 +00:00
books/client/view/form.js

334 lines
9.8 KiB
JavaScript
Raw Normal View History

2018-01-16 06:09:17 +00:00
const frappe = require('frappejs');
2018-01-12 12:25:07 +00:00
const controls = require('./controls');
const FormLayout = require('./formLayout');
2018-01-31 10:13:33 +00:00
const Observable = require('frappejs/utils/observable');
const keyboard = require('frappejs/client/ui/keyboard');
2018-01-12 12:25:07 +00:00
2018-01-31 10:13:33 +00:00
module.exports = class BaseForm extends Observable {
2018-03-27 13:55:26 +00:00
constructor({doctype, parent, submit_label='Submit', container, meta, inline=false}) {
2018-01-31 10:13:33 +00:00
super();
2018-02-08 09:38:47 +00:00
Object.assign(this, arguments[0]);
2018-03-26 08:53:46 +00:00
this.links = [];
2018-01-12 12:25:07 +00:00
this.meta = frappe.getMeta(this.doctype);
2018-03-27 13:55:26 +00:00
2018-01-24 11:52:05 +00:00
if (this.setup) {
this.setup();
}
2018-03-27 13:55:26 +00:00
2018-01-12 12:25:07 +00:00
this.make();
2018-03-08 13:31:22 +00:00
this.bindFormEvents();
2018-03-27 13:55:26 +00:00
if (this.doc) {
// bootstrapped with a doc
this.bindEvents(this.doc);
}
2018-01-12 12:25:07 +00:00
}
make() {
if (this.body || !this.parent) {
return;
}
2018-03-27 13:55:26 +00:00
if (this.inline) {
this.body = this.parent
} else {
this.body = frappe.ui.add('div', 'form-body', this.parent);
}
if (this.actions) {
this.makeToolbar();
}
2018-01-12 12:25:07 +00:00
2018-02-09 12:55:55 +00:00
this.form = frappe.ui.add('form', 'form-container', this.body);
2018-03-27 13:55:26 +00:00
if (this.inline) {
this.form.classList.add('form-inline');
}
2018-02-09 12:55:55 +00:00
this.form.onValidate = true;
this.formLayout = new FormLayout({
fields: this.meta.fields,
layout: this.meta.layout
});
this.form.appendChild(this.formLayout.form);
this.bindKeyboard();
2018-02-09 12:55:55 +00:00
}
2018-03-08 13:31:22 +00:00
bindFormEvents() {
if (this.meta.formEvents) {
for (let key in this.meta.formEvents) {
this.on(key, this.meta.formEvents[key]);
}
}
}
2018-02-08 09:38:47 +00:00
makeToolbar() {
if (this.actions.includes('save')) {
this.makeSaveButton();
if (this.meta.isSubmittable) {
this.makeSubmitButton();
2018-03-05 16:45:21 +00:00
this.makeRevertButton();
}
}
if (this.meta.print && this.actions.includes('print')) {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._("Print"), async (e) => {
await frappe.router.setRoute('print', this.doctype, this.doc.name);
});
}
2018-02-14 12:50:56 +00:00
if (!this.meta.isSingle && this.actions.includes('delete')) {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._("Delete"), async (e) => {
2018-02-20 09:53:38 +00:00
await this.delete();
});
}
2018-02-14 12:50:56 +00:00
if (!this.meta.isSingle && this.actions.includes('duplicate')) {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._('Duplicate'), async () => {
let newDoc = await frappe.getDuplicate(this.doc);
await frappe.router.setRoute('edit', newDoc.doctype, newDoc.name);
newDoc.set('name', '');
});
}
if (this.meta.settings && this.actions.includes('settings')) {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._('Settings...'), () => {
frappe.desk.showFormModal(this.meta.settings, this.meta.settings);
2018-02-14 12:50:56 +00:00
});
}
}
2018-01-23 08:00:29 +00:00
makeSaveButton() {
this.saveButton = this.container.addButton(frappe._("Save"), 'primary', async (event) => {
await this.save();
});
this.on('change', () => {
const show = this.doc._dirty && !this.doc.submitted;
this.saveButton.classList.toggle('hide', !show);
});
}
makeSubmitButton() {
this.submitButton = this.container.addButton(frappe._("Submit"), 'primary', async (event) => {
await this.submit();
});
this.on('change', () => {
const show = this.meta.isSubmittable && !this.doc._dirty && !this.doc.submitted;
this.submitButton.classList.toggle('hide', !show);
});
2018-03-05 16:45:21 +00:00
}
2018-03-05 16:45:21 +00:00
makeRevertButton() {
this.revertButton = this.container.addButton(frappe._("Revert"), 'secondary', async (event) => {
await this.revert();
});
this.on('change', () => {
const show = this.meta.isSubmittable && !this.doc._dirty && this.doc.submitted;
this.revertButton.classList.toggle('hide', !show);
});
}
bindKeyboard() {
keyboard.bindKey(this.form, 'ctrl+s', (e) => {
if (document.activeElement) {
document.activeElement.blur();
}
e.preventDefault();
if (this.doc._notInserted || this.doc._dirty) {
this.save();
} else {
if (this.meta.isSubmittable && !this.doc.submitted) this.submit();
}
2018-01-12 12:25:07 +00:00
});
}
async setDoc(doctype, name) {
this.doc = await frappe.getDoc(doctype, name);
this.bindEvents(this.doc);
if (this.doc._notInserted && !this.doc._nameCleared) {
this.doc._nameCleared = true;
// flag so that name is cleared only once
await this.doc.set('name', '');
}
2018-02-15 09:53:28 +00:00
this.setTitle();
frappe._curFrm = this;
2018-02-15 09:53:28 +00:00
}
setTitle() {
2018-03-27 13:55:26 +00:00
if (!this.container) return;
const doctypeLabel = this.doc.meta.label || this.doc.meta.name;
2018-03-05 16:45:21 +00:00
if (this.doc.meta.isSingle || this.doc.meta.naming === 'random') {
this.container.setTitle(doctypeLabel);
2018-02-15 09:53:28 +00:00
} else if (this.doc._notInserted) {
this.container.setTitle(frappe._('New {0}', doctypeLabel));
2018-02-15 09:53:28 +00:00
} else {
2018-02-22 07:36:28 +00:00
this.container.setTitle(this.doc.name);
2018-02-15 09:53:28 +00:00
}
2018-03-05 16:45:21 +00:00
if (this.doc.submitted) {
2018-03-07 10:37:58 +00:00
// this.container.addTitleBadge('✓', frappe._('Submitted'));
2018-03-05 16:45:21 +00:00
}
}
2018-03-26 08:53:46 +00:00
setLinks(label, options) {
// set links to helpful reports as identified by this.meta.links
if (this.meta.links) {
let links = this.getLinks();
if (!links.equals(this.links)) {
this.refreshLinks(links);
this.links = links;
}
}
}
getLinks() {
let links = [];
for (let link of this.meta.links) {
if (link.condition(this)) {
links.push(link);
}
}
return links;
}
refreshLinks(links) {
2018-03-27 13:55:26 +00:00
if (!this.container) return;
2018-03-26 08:53:46 +00:00
this.container.clearLinks();
for(let link of links) {
// make the link
this.container.addLink(link.label, () => {
let options = link.action(this);
if (options) {
if (options.params) {
// set route parameters
frappe.params = options.params;
}
if (options.route) {
// go to the given route
frappe.router.setRoute(...options.route);
}
}
});
}
}
async bindEvents(doc) {
if (this.doc && this.docListener) {
// stop listening to the old doc
this.doc.off(this.docListener);
2018-01-12 12:25:07 +00:00
}
this.doc = doc;
for (let control of this.formLayout.controlList) {
2018-01-12 12:25:07 +00:00
control.bind(this.doc);
}
2018-03-08 13:31:22 +00:00
this.refresh();
this.setupDocListener();
2018-02-09 12:55:55 +00:00
this.trigger('use', {doc:doc});
}
setupDocListener() {
// refresh value in control
this.docListener = (params) => {
2018-02-08 11:45:32 +00:00
if (params.fieldname) {
// only single value changed
let control = this.formLayout.controls[params.fieldname];
2018-02-08 11:45:32 +00:00
if (control && control.getInputValue() !== control.format(params.fieldname)) {
2018-02-19 06:31:07 +00:00
control.refresh();
2018-02-08 11:45:32 +00:00
}
} else {
// multiple values changed
this.refresh();
}
this.trigger('change');
2018-02-09 12:55:55 +00:00
this.form.classList.remove('was-validated');
};
this.doc.on('change', this.docListener);
this.trigger('change');
2018-01-12 12:25:07 +00:00
}
2018-02-12 09:42:26 +00:00
checkValidity() {
let validity = this.form.checkValidity();
if (validity) {
for (let control of this.formLayout.controlList) {
2018-02-12 09:42:26 +00:00
// check validity in table
if (control.fieldtype==='Table') {
validity = control.checkValidity();
if (!validity) {
break;
}
}
}
}
return validity;
}
refresh() {
for(let control of this.formLayout.controlList) {
control.refresh();
}
2018-03-08 13:31:22 +00:00
this.trigger('refresh', this);
2018-03-26 08:53:46 +00:00
this.setLinks();
}
2018-01-12 12:25:07 +00:00
async submit() {
this.doc.submitted = 1;
await this.save();
}
2018-03-05 16:45:21 +00:00
async revert() {
this.doc.submitted = 0;
await this.save();
}
async save() {
2018-02-12 09:42:26 +00:00
if (!this.checkValidity()) {
2018-02-09 12:55:55 +00:00
this.form.classList.add('was-validated');
return;
}
2018-01-12 12:25:07 +00:00
try {
2018-03-05 16:45:21 +00:00
let oldName = this.doc.name;
2018-02-09 12:55:55 +00:00
if (this.doc._notInserted) {
2018-01-12 12:25:07 +00:00
await this.doc.insert();
} else {
await this.doc.update();
}
frappe.ui.showAlert({message: frappe._('Saved'), color: 'green'});
2018-03-05 16:45:21 +00:00
if (oldName !== this.doc.name) {
frappe.router.setRoute('edit', this.doctype, this.doc.name);
return;
}
this.refresh();
this.trigger('change');
2018-01-12 12:25:07 +00:00
} catch (e) {
frappe.ui.showAlert({message: frappe._('Failed'), color: 'red'});
2018-02-09 12:55:55 +00:00
return;
2018-01-12 12:25:07 +00:00
}
await this.trigger('save');
2018-01-12 12:25:07 +00:00
}
2018-02-20 09:53:38 +00:00
async delete() {
try {
await this.doc.delete();
frappe.ui.showAlert({message: frappe._('Deleted'), color: 'green'});
2018-02-20 09:53:38 +00:00
this.trigger('delete');
} catch (e) {
frappe.ui.showAlert({message: e, color: 'red'});
2018-01-31 10:13:33 +00:00
}
}
}