seitime-frappe/frappe/public/js/frappe/form/script_manager.js

290 lines
7.5 KiB
JavaScript

// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.provide("frappe.ui.form.handlers");
window.extend_cscript = (cscript, controller_object) => {
$.extend(cscript, controller_object);
if (cscript && controller_object) {
cscript.__proto__ = controller_object.__proto__;
}
return cscript;
};
frappe.ui.form.get_event_handler_list = function (doctype, fieldname) {
if (!frappe.ui.form.handlers[doctype]) {
frappe.ui.form.handlers[doctype] = {};
}
if (!frappe.ui.form.handlers[doctype][fieldname]) {
frappe.ui.form.handlers[doctype][fieldname] = [];
}
return frappe.ui.form.handlers[doctype][fieldname];
};
frappe.ui.form.on = frappe.ui.form.on_change = function (doctype, fieldname, handler) {
var add_handler = function (fieldname, handler) {
var handler_list = frappe.ui.form.get_event_handler_list(doctype, fieldname);
let _handler = (...args) => {
try {
return handler(...args);
} catch (error) {
console.error(handler);
throw error;
}
};
handler_list.push(_handler);
// add last handler to events so it can be called as
// frm.events.handler(frm)
if (cur_frm && cur_frm.doctype === doctype) {
cur_frm.events[fieldname] = _handler;
}
};
if (!handler && $.isPlainObject(fieldname)) {
// a dict of handlers {fieldname: handler, ...}
for (var key in fieldname) {
var fn = fieldname[key];
if (typeof fn === "function") {
add_handler(key, fn);
}
}
} else {
add_handler(fieldname, handler);
}
};
// remove standard event handlers
frappe.ui.form.off = function (doctype, fieldname, handler) {
var handler_list = frappe.ui.form.get_event_handler_list(doctype, fieldname);
if (handler_list.length) {
frappe.ui.form.handlers[doctype][fieldname] = [];
}
if (cur_frm && cur_frm.doctype === doctype && cur_frm.events[fieldname]) {
delete cur_frm.events[fieldname];
}
if (cur_frm && cur_frm.cscript && cur_frm.cscript[fieldname]) {
delete cur_frm.cscript[fieldname];
}
};
frappe.ui.form.trigger = function (doctype, fieldname) {
cur_frm.script_manager.trigger(fieldname, doctype);
};
frappe.ui.form.ScriptManager = class ScriptManager {
constructor(opts) {
$.extend(this, opts);
}
make(ControllerClass) {
this.frm.cscript = extend_cscript(
this.frm.cscript,
new ControllerClass({ frm: this.frm })
);
}
trigger(event_name, doctype, name) {
// trigger all the form level events that
// are bound to this event_name
let me = this;
doctype = doctype || this.frm.doctype;
name = name || this.frm.docname;
let tasks = [];
let handlers = this.get_handlers(event_name, doctype);
// helper for child table
this.frm.selected_doc = frappe.get_doc(doctype, name);
let runner = (_function, is_old_style) => {
let _promise = null;
if (is_old_style) {
// old style arguments (doc, cdt, cdn)
_promise = me.frm.cscript[_function](me.frm.doc, doctype, name);
} else {
// new style (frm, doctype, name)
_promise = _function(me.frm, doctype, name);
}
// if the trigger returns a promise, return it,
// or use the default promise frappe.after_ajax
if (_promise && _promise.then) {
return _promise;
} else {
return frappe.after_server_call();
}
};
// make list of functions to be run serially
handlers.new_style.forEach((_function) => {
if (event_name === "setup") {
// setup must be called immediately
runner(_function, false);
} else {
tasks.push(() => runner(_function, false));
}
});
handlers.old_style.forEach((_function) => {
if (event_name === "setup") {
// setup must be called immediately
runner(_function, true);
} else {
tasks.push(() => runner(_function, true));
}
});
// run them serially
return frappe.run_serially(tasks);
}
has_handler(event_name) {
// return true if there exist an event handler (new style only)
return (
frappe.ui.form.handlers[this.frm.doctype] &&
frappe.ui.form.handlers[this.frm.doctype][event_name]
);
}
has_handlers(event_name, doctype) {
let handlers = this.get_handlers(event_name, doctype);
return handlers && (handlers.old_style.length || handlers.new_style.length);
}
get_handlers(event_name, doctype) {
// returns list of all functions to be called (old style and new style)
let me = this;
let handlers = {
old_style: [],
new_style: [],
};
if (frappe.ui.form.handlers[doctype] && frappe.ui.form.handlers[doctype][event_name]) {
$.each(frappe.ui.form.handlers[doctype][event_name], function (i, fn) {
handlers.new_style.push(fn);
});
}
if (frappe.ui.form.handlers["*"] && frappe.ui.form.handlers["*"][event_name]) {
$.each(frappe.ui.form.handlers["*"][event_name], function (i, fn) {
handlers.new_style.push(fn);
});
}
if (this.frm.cscript && this.frm.cscript[event_name]) {
handlers.old_style.push(event_name);
}
if (this.frm.cscript && this.frm.cscript["custom_" + event_name]) {
handlers.old_style.push("custom_" + event_name);
}
return handlers;
}
setup() {
const doctype = this.frm.meta;
const me = this;
let client_script = doctype.__js;
// append the custom script for this form's layout
if (this.frm.doctype_layout?.client_script) {
// add a newline to avoid conflict with doctype JS
client_script += `\n${this.frm.doctype_layout.client_script}`;
}
if (client_script) {
new Function(client_script)();
}
if (!this.frm.doctype_layout && doctype.__custom_js) {
try {
new Function(doctype.__custom_js)();
} catch (e) {
frappe.msgprint({
title: __("Error in Client Script"),
indicator: "orange",
message: '<pre class="small"><code>' + e.stack + "</code></pre>",
});
}
}
function setup_add_fetch(df) {
let is_read_only_field =
[
"Data",
"Read Only",
"Text",
"Small Text",
"Currency",
"Check",
"Text Editor",
"Attach Image",
"Code",
"Link",
"Float",
"Int",
"Date",
"Datetime",
"Select",
"Duration",
"Time",
"Percent",
"Phone",
"Barcode",
"Autocomplete",
"Icon",
"Color",
"Rating",
].includes(df.fieldtype) ||
df.read_only == 1 ||
df.is_virtual == 1;
if (is_read_only_field && df.fetch_from && df.fetch_from.indexOf(".") != -1) {
var parts = df.fetch_from.split(".");
me.frm.add_fetch(parts[0], parts[1], df.fieldname, df.parent);
}
}
// setup add fetch
$.each(this.frm.fields, function (i, field) {
setup_add_fetch(field.df);
if (frappe.model.table_fields.includes(field.df.fieldtype)) {
$.each(
frappe.meta.get_docfields(field.df.options, me.frm.docname),
function (i, df) {
setup_add_fetch(df);
}
);
}
});
// css
doctype.__css && frappe.dom.set_style(doctype.__css);
this.trigger("setup");
}
log_error(caller, e) {
frappe.show_alert({ message: __("Error in Client Script."), indicator: "error" });
console.group && console.group();
console.log("----- error in client script -----");
console.log("method: " + caller);
console.log(e);
console.log("error message: " + e.message);
console.trace && console.trace();
console.log("----- end of error message -----");
console.group && console.groupEnd();
}
copy_from_first_row(parentfield, current_row, fieldnames) {
var data = this.frm.doc[parentfield];
if (data.length === 1 || data[0] === current_row) return;
if (typeof fieldnames === "string") {
fieldnames = [fieldnames];
}
$.each(fieldnames, function (i, fieldname) {
frappe.model.set_value(
current_row.doctype,
current_row.name,
fieldname,
data[0][fieldname]
);
});
}
};