mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-22 07:45:09 +00:00
6256 lines
No EOL
192 KiB
JavaScript
6256 lines
No EOL
192 KiB
JavaScript
frappe.templates['grid_form'] = '<div class="grid-form-heading"> <div class="toolbar grid-header-toolbar"> <span class="panel-title"> {%= __("Editing Row") %} #<span class="grid-form-row-index"></span></span> <button class="btn btn-default btn-xs pull-right" style="margin-left: 7px;"> <i class="octicon octicon-check visible-xs" style="padding-bottom: 2px;"></i> <span class="hidden-xs octicon octicon-triangle-up"></span></button> <button class="btn btn-default btn-xs pull-right grid-insert-row" style="margin-left: 7px;"> {%= __("Insert Above") %}</button> <button class="btn btn-default btn-xs pull-right grid-insert-row-below hidden-xs" style="margin-left: 7px;"> {%= __("Insert Below") %}</button> <button class="btn btn-danger btn-xs pull-right grid-delete-row"> <i class="octicon octicon-trashcan" style="padding-bottom: 2px; margin-top: 1px;"></i> </button> </div> </div> <div class="grid-form-body"> <div class="form-area"></div> <div class="grid-footer-toolbar clearfix hidden-xs"> <span class="text-muted"> <i class="octicon octicon-keyboard"></i> – <kbd>{%= __("Ctrl + Up") %}</kbd>, <kbd>{%= __("Ctrl + Down") %}</kbd>, <kbd>{%= __("ESC") %}</kbd> </span> <button class="btn btn-default btn-xs pull-right grid-append-row" style="margin-left: 7px;"> {%= __("Insert Below") %}</button> </div> </div> ';
|
|
frappe.templates['grid_body'] = '<div> <div class="form-grid"> <div class="grid-heading-row"></div> <div class="grid-body"> <div class="rows"></div> <div class="grid-empty text-center hide">{%= __("No Data") %}</div> <div class="small form-clickable-section grid-footer"> <div class="row"> <div class="col-sm-6 grid-buttons"> <button type="reset" class="btn btn-xs btn-danger grid-remove-rows hide"> {%= __("Delete") %}</button> <button type="reset" class="grid-add-multiple-rows btn btn-xs btn-default hide" style="margin-right: 10px;"> {%= __("Add Multiple") %}</a> <button type="reset" class="btn btn-xs btn-default grid-add-row"> {%= __("Add Row") %}</button> </div> <div class="col-sm-6 text-right"> <a href="#" class="grid-download btn btn-xs btn-default hide" style="margin-left: 10px;"> {%= __("Download") %}</a> <a href="#" class="grid-upload btn btn-xs btn-default hide" style="margin-left: 10px;"> {%= __("Upload") %}</a> </div> </div> </div> </div> </div> </div> ';
|
|
frappe.templates['print_layout'] = '<div class="form-print-wrapper"> <div class="print-toolbar row"> <div class="col-xs-2"> <select class="print-preview-select input-sm form-control"></select></div> <div class="col-xs-2"> <select class="languages input-sm form-control"></select></div> <div class="col-xs-2"> <div class="checkbox small" style="margin-top: 7px; margin-bottom: 0px;"> <label> <input type="checkbox" class="print-letterhead text-muted" style="margin-top: 1px;"/> {%= __("Letter Head") %}</label> </div> </div> <div class="col-xs-6 text-right"> <div class="btn-group"> <a class="btn-print-print btn-sm btn btn-default"> <strong>{%= __("Print") %}</strong></a> <a class="btn-print-edit btn-sm btn btn-default"> {%= __("Customize") %}</a> <a class="btn-print-preview btn-sm btn btn-default"> {%= __("Full Page") %}</a> <a class="btn-download-pdf btn-sm btn btn-default"> {%= __("PDF") %}</a> </div> </div> </div> <div class="print-preview-wrapper"> <div class="print-preview"> <div class="print-format"></div> </div> </div> </div> ';
|
|
frappe.templates['users_in_sidebar'] = '{% for (var i=0, l=users.length; i < l; i++) { var u = users[i]; %} <span class="avatar avatar-small {{ u.avatar_class || "" }}" title="{{ u.title }}"> {% if (u.icon) { %} <i class="{{ u.icon }}"></i> {% } else if(u.image) { %} <img class="media-object" src="{{ u.image }}" alt="{{ u.fullname }}"> {% } else { %} <div class="standard-image" style="background-color: {{ u.color }};">{{ u.abbr.substr(0,1) }}</div> {% } %} </span> {% } %} ';
|
|
frappe.templates['set_sharing'] = '<div class="padding"> <div class="row"> <div class="col-xs-6"><h6>{%= __("User") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Read") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Write") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Share") %}</h6></div> </div> <div class="row shared-user" data-everyone=1> <div class="col-xs-6 share-all" style="height: 30px;"><b>{{ __("Everyone") }}</b></div> <div class="col-xs-2"><input type="checkbox" name="read" {% if(cint(everyone.read)) { %}checked{% } %} class="edit-share"></div> <div class="col-xs-2"><input type="checkbox" name="write" {% if(cint(everyone.write)) { %}checked{% } %} class="edit-share"{% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}></div> <div class="col-xs-2"><input type="checkbox" name="share" {% if(cint(everyone.share)) { %}checked{% } %} class="edit-share"></div> </div> {% for (var i=0, l=shared.length; i < l; i++) { var s = shared[i]; %} {% if(s && !s.everyone) { %} <div class="row shared-user" data-user="{%= s.user %}" data-name="{%= s.name %}"> <div class="col-xs-6">{%= s.user %}</div> <div class="col-xs-2"><input type="checkbox" name="read" {% if(cint(s.read)) { %}checked{% } %} class="edit-share"></div> <div class="col-xs-2"><input type="checkbox" name="write" {% if(cint(s.write)) { %}checked{% } %} class="edit-share"{% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}></div> <div class="col-xs-2"><input type="checkbox" name="share" {% if(cint(s.share)) { %}checked{% } %} class="edit-share"></div> </div> {% } %} {% } %} {% if(frappe.model.can_share(null, frm)) { %} <hr> <div class="row"> <div class="col-xs-6"><h6>{%= __("Share this document with") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Read") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Write") %}</h6></div> <div class="col-xs-2"><h6>{%= __("Can Share") %}</h6></div> </div> <div class="row"> <div class="col-xs-6 input-wrapper-add-share"></div> <div class="col-xs-2"><input type="checkbox" class="add-share-read" name="read"></div> <div class="col-xs-2"><input type="checkbox" class="add-share-write" name="write" {% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}></div> <div class="col-xs-2"><input type="checkbox" class="add-share-share" name="share"></div> </div> <p> <button class="btn btn-primary btn-add-share">{%= __("Add") %}</button> </p> {% } %} </div> ';
|
|
frappe.templates['form_sidebar'] = '<ul class="list-unstyled sidebar-menu user-actions hidden"></ul> <ul class="list-unstyled sidebar-menu sidebar-image-section hidden-xs hidden-sm hide"> <li class="divider"></li> <li class="sidebar-image-wrapper"> <div class="sidebar-image"></div> <div class="sidebar-standard-image"> <div class="standard-image"></div> </div> </li> </ul> {% if frm.meta.beta %} <div class="sidebar-menu"> <p><label class="label label-warning" title="{{ __("This feature is brand new and still experimental") }}">{{ __("Under Development") }}</label></p> <p><a class="small" href="https://github.com/frappe/{{ frappe.boot.module_app[frappe.scrub(frm.meta.module)] }}/issues/new" target="_blank"> {{ __("Click here to post bugs and suggestions") }}</a></p> </div> {% endif %} <ul class="list-unstyled sidebar-menu sidebar-rating hide"> <li class="divider"></li> <li style="position: relative;"> <a class="strong badge-hover"> <span>{%= __("Feedback") %}</span> </a> </li> <li class="rating-icons"></li> </ul> <ul class="list-unstyled sidebar-menu"> <li class="divider"></li> <li style="position: relative;"> <a class="strong sidebar-comments badge-hover"> <span>{%= __("Comments") %}</span> <span class="badge n-comments">0</span> </a> </li> {% if(frappe.help.has_help(doctype)) { %} <li><a class="strong help-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li> {% } %} </ul> <ul class="list-unstyled sidebar-menu form-assignments"> <li class="divider"></li> <li class="h6 assigned-to-label">{%= __("Assigned To") %}</li> <li><a class="strong add-assignment">{%= __("Assign") %} <i class="octicon octicon-plus" style="margin-left: 2px;"></i></a></li> </ul> <ul class="list-unstyled sidebar-menu form-attachments"> <li class="divider"></li> <li class="h6 attachments-label">{%= __("Attachments") %}</li> <li><a class="strong add-attachment">{%= __("Attach File") %} <i class="octicon octicon-plus" style="margin-left: 2px;"></i></li></a> </ul> <ul class="list-unstyled sidebar-menu"> <li class="divider"></li> <li class="h6 tags-label">{%= __("Tags") %}</li> <li class="form-tags"> <div class="tag-area"></div> <div class="clearfix"></div> </li> </ul> <ul class="list-unstyled sidebar-menu"> <li class="divider"></li> <li class="h6 shared-with-label">{%= __("Shared With") %}</li> <li class="form-shared"></li> </ul> <ul class="list-unstyled sidebar-menu"> <li class="divider"></li> <li class="h6 viewers-label">{%= __("Currently Viewing") %}</li> <li class="form-viewers"></li> </ul> <ul class="list-unstyled sidebar-menu text-muted"> <li class="liked-by-parent"> <span class="liked-by"> <i class="octicon octicon-heart like-action text-extra-muted fa-fw"></i> <span class="likes-count"></span> </span> </li> <li class="modified-by"></li> <li class="created-by"></li> </ul> {% if(frappe.get_form_sidebar_extension) { %} {{ frappe.get_form_sidebar_extension() }} {% } %} <ul class="list-unstyled visible-xs visible-sm"> <li class="divider"></li> <li class="close-sidebar">Close</li> </ul>';
|
|
frappe.templates['form_dashboard'] = '<div class="form-dashboard-wrapper"> <div class="progress-area hidden form-dashboard-section"> </div> <div class="form-heatmap hidden form-dashboard-section"> <div id="heatmap-{{ frappe.model.scrub(frm.doctype) }}"></div> <div class="text-muted small heatmap-message hidden"></div> </div> <div class="form-graph form-dashboard-section hidden"></div> <div class="form-stats form-dashboard-section hidden"> <div class="row"></div> </div> <div class="form-links form-dashboard-section hidden"> <div class="transactions"></div> </div> </div>';
|
|
frappe.templates['form_document_flow'] = '<div class="document-flow"> {% for dt in doctypes %} <span class="document-flow-link-wrapper"> <a data-doctype="{{ dt }}" class="document-flow-link {% if (dt===frm.doctype) { %} strong disabled {% } %} " style="color: inherit;"> <span class="indicator {% if (dt===frm.doctype) { %} blue {% } else { %} darkgrey {% } %}"></span><br> <span class="document-flow-link-label">{{ __(dt) }}</span> </a> </span> {% endfor %} </div> ';
|
|
frappe.templates['form_links'] = '<div class="form-documents"> {% for (var i=0; i < transactions.length; i++) { %} {% if((i % 2)===0) { %}<div class="row">{% } %} <div class="col-xs-6"> <h6>{{ transactions[i].label }}</h6> {% for (var j=0; j < transactions[i].items.length; j++) { var doctype = transactions[i].items[j]; %} <div class="document-link" data-doctype="{{ doctype }}"> <a class="badge-link small">{{ __(doctype) }}</a> <span class="text-muted small count"></span> <span class="open-notification hidden" title="{{ __("Open {0}", [__(doctype)])}}"></span> {% if !internal_links[doctype] %} <button class="btn btn-new btn-default btn-xs hidden" data-doctype="{{ doctype }}"> <i class="octicon octicon-plus" style="font-size: 12px;"></i></button> {% endif %} </div> {% } %} </div> {% if((i % 2)===1) { %}</div>{% } %} {% } %} {% if((i % 2)===0) { %}</div>{% } %} </div> ';
|
|
|
|
|
|
frappe.provide('frappe.views.formview');
|
|
|
|
frappe.views.FormFactory = frappe.views.Factory.extend({
|
|
make: function make(route) {
|
|
var me = this,
|
|
dt = route[1];
|
|
|
|
if (!frappe.views.formview[dt]) {
|
|
frappe.model.with_doctype(dt, function () {
|
|
me.page = frappe.container.add_page("Form/" + dt);
|
|
frappe.views.formview[dt] = me.page;
|
|
me.page.frm = new _f.Frm(dt, me.page, true);
|
|
me.show_doc(route);
|
|
});
|
|
} else {
|
|
me.show_doc(route);
|
|
}
|
|
|
|
if (!this.initialized) {
|
|
$(document).on("page-change", function () {
|
|
frappe.ui.form.close_grid_form();
|
|
});
|
|
|
|
frappe.realtime.on("new_communication", function (data) {
|
|
frappe.timeline.new_communication(data);
|
|
});
|
|
|
|
frappe.realtime.on("delete_communication", function (data) {
|
|
frappe.timeline.delete_communication(data);
|
|
});
|
|
|
|
frappe.realtime.on('update_communication', function (data) {
|
|
frappe.timeline.update_communication(data);
|
|
});
|
|
|
|
frappe.realtime.on("doc_viewers", function (data) {
|
|
frappe.ui.form.set_viewers(data);
|
|
});
|
|
}
|
|
|
|
this.initialized = true;
|
|
},
|
|
show_doc: function show_doc(route) {
|
|
var dt = route[1],
|
|
dn = route.slice(2).join("/"),
|
|
me = this;
|
|
|
|
if (frappe.model.new_names[dn]) {
|
|
dn = frappe.model.new_names[dn];
|
|
frappe.set_route("Form", dt, dn);
|
|
return;
|
|
}
|
|
|
|
frappe.model.with_doc(dt, dn, function (dn, r) {
|
|
if (r && r['403']) return;
|
|
|
|
if (!(locals[dt] && locals[dt][dn])) {
|
|
var new_str = __("New") + " ";
|
|
if (dn && dn.substr(0, new_str.length) == new_str) {
|
|
var new_name = frappe.model.make_new_doc_and_get_name(dt, true);
|
|
if (new_name === dn) {
|
|
me.load(dt, dn);
|
|
} else {
|
|
frappe.set_route("Form", dt, new_name);
|
|
}
|
|
} else {
|
|
frappe.show_not_found(route);
|
|
}
|
|
return;
|
|
}
|
|
me.load(dt, dn);
|
|
});
|
|
},
|
|
load: function load(dt, dn) {
|
|
frappe.container.change_to("Form/" + dt);
|
|
frappe.views.formview[dt].frm.refresh(dn);
|
|
}
|
|
});
|
|
|
|
frappe.provide('_f');
|
|
frappe.provide('frappe.ui.form');
|
|
|
|
frappe.ui.form.Controller = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
}
|
|
});
|
|
|
|
_f.frms = {};
|
|
|
|
_f.Frm = function (doctype, parent, in_form) {
|
|
this.docname = '';
|
|
this.doctype = doctype;
|
|
this.hidden = false;
|
|
this.refresh_if_stale_for = 120;
|
|
|
|
var me = this;
|
|
this.opendocs = {};
|
|
this.custom_buttons = {};
|
|
this.sections = [];
|
|
this.grids = [];
|
|
this.cscript = new frappe.ui.form.Controller({ frm: this });
|
|
this.events = {};
|
|
this.pformat = {};
|
|
this.fetch_dict = {};
|
|
this.parent = parent;
|
|
this.tinymce_id_list = [];
|
|
|
|
this.setup_meta(doctype);
|
|
|
|
this.in_form = in_form ? true : false;
|
|
|
|
var me = this;
|
|
$(document).on('rename', function (event, dt, old_name, new_name) {
|
|
if (dt == me.doctype) me.rename_notify(dt, old_name, new_name);
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.check_doctype_conflict = function (docname) {
|
|
var me = this;
|
|
if (this.doctype == 'DocType' && docname == 'DocType') {
|
|
frappe.msgprint(__('Allowing DocType, DocType. Be careful!'));
|
|
} else if (this.doctype == 'DocType') {
|
|
if (frappe.views.formview[docname] || frappe.pages['List/' + docname]) {
|
|
window.location.reload();
|
|
}
|
|
} else {
|
|
if (frappe.views.formview.DocType && frappe.views.formview.DocType.frm.opendocs[this.doctype]) {
|
|
window.location.reload();
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.setup = function () {
|
|
var me = this;
|
|
this.fields = [];
|
|
this.fields_dict = {};
|
|
this.state_fieldname = frappe.workflow.get_state_fieldname(this.doctype);
|
|
|
|
this.wrapper = this.parent;
|
|
this.$wrapper = $(this.wrapper);
|
|
frappe.ui.make_app_page({
|
|
parent: this.wrapper,
|
|
single_column: this.meta.hide_toolbar
|
|
});
|
|
this.page = this.wrapper.page;
|
|
this.layout_main = this.page.main.get(0);
|
|
|
|
this.toolbar = new frappe.ui.form.Toolbar({
|
|
frm: this,
|
|
page: this.page
|
|
});
|
|
|
|
this.setup_print_layout();
|
|
|
|
this.setup_std_layout();
|
|
|
|
this.script_manager = new frappe.ui.form.ScriptManager({
|
|
frm: this
|
|
});
|
|
this.script_manager.setup();
|
|
this.watch_model_updates();
|
|
|
|
if (!this.meta.hide_toolbar) {
|
|
this.footer = new frappe.ui.form.Footer({
|
|
frm: this,
|
|
parent: $('<div>').appendTo(this.page.main.parent())
|
|
});
|
|
$("body").attr("data-sidebar", 1);
|
|
}
|
|
this.setup_drag_drop();
|
|
|
|
this.setup_done = true;
|
|
};
|
|
|
|
_f.Frm.prototype.setup_drag_drop = function () {
|
|
var me = this;
|
|
this.$wrapper.on('dragenter dragover', false).on('drop', function (e) {
|
|
var dataTransfer = e.originalEvent.dataTransfer;
|
|
if (!(dataTransfer && dataTransfer.files && dataTransfer.files.length > 0)) {
|
|
return;
|
|
}
|
|
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
if (me.doc.__islocal) {
|
|
frappe.msgprint(__("Please save before attaching."));
|
|
throw "attach error";
|
|
}
|
|
|
|
if (me.attachments.max_reached()) {
|
|
frappe.msgprint(__("Maximum Attachment Limit for this record reached."));
|
|
throw "attach error";
|
|
}
|
|
|
|
frappe.upload.make({
|
|
args: me.attachments.get_args(),
|
|
files: dataTransfer.files,
|
|
callback: function callback(attachment, r) {
|
|
me.attachments.attachment_uploaded(attachment, r);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.setup_print_layout = function () {
|
|
var me = this;
|
|
this.print_preview = new frappe.ui.form.PrintPreview({
|
|
frm: this
|
|
});
|
|
|
|
this.page.wrapper.on('view-change', function () {
|
|
me.toolbar.set_primary_action();
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.print_doc = function () {
|
|
if (this.print_preview.wrapper.is(":visible")) {
|
|
this.hide_print();
|
|
return;
|
|
}
|
|
if (!frappe.model.can_print(this.doc.doctype, this)) {
|
|
frappe.msgprint(__("You are not allowed to print this document"));
|
|
return;
|
|
}
|
|
|
|
this.print_preview.refresh_print_options().trigger("change");
|
|
this.page.set_view("print");
|
|
this.print_preview.set_user_lang();
|
|
};
|
|
|
|
_f.Frm.prototype.hide_print = function () {
|
|
if (this.setup_done && this.page.current_view_name === "print") {
|
|
this.page.set_view(this.page.previous_view_name === "print" ? "main" : this.page.previous_view_name || "main");
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.watch_model_updates = function () {
|
|
var me = this;
|
|
|
|
frappe.model.on(me.doctype, "*", function (fieldname, value, doc) {
|
|
if (doc.name === me.docname) {
|
|
me.dirty();
|
|
me.fields_dict[fieldname] && me.fields_dict[fieldname].refresh(fieldname);
|
|
|
|
me.layout.refresh_dependency();
|
|
return me.script_manager.trigger(fieldname, doc.doctype, doc.name);
|
|
}
|
|
});
|
|
|
|
var table_fields = frappe.get_children("DocType", me.doctype, "fields", { fieldtype: "Table" });
|
|
|
|
$.each(table_fields, function (i, df) {
|
|
frappe.model.on(df.options, "*", function (fieldname, value, doc) {
|
|
if (doc.parent === me.docname && doc.parentfield === df.fieldname) {
|
|
me.dirty();
|
|
me.fields_dict[df.fieldname].grid.set_value(fieldname, value, doc);
|
|
me.script_manager.trigger(fieldname, doc.doctype, doc.name);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.setup_std_layout = function () {
|
|
this.form_wrapper = $('<div></div>').appendTo(this.layout_main);
|
|
this.body = $('<div></div>').appendTo(this.form_wrapper);
|
|
|
|
this.meta.section_style = 'Simple';
|
|
this.layout = new frappe.ui.form.Layout({
|
|
parent: this.body,
|
|
doctype: this.doctype,
|
|
frm: this,
|
|
with_dashboard: true
|
|
});
|
|
this.layout.make();
|
|
|
|
this.fields_dict = this.layout.fields_dict;
|
|
this.fields = this.layout.fields_list;
|
|
|
|
this.document_flow = new frappe.ui.form.DocumentFlow({
|
|
frm: this
|
|
});
|
|
|
|
this.dashboard = new frappe.ui.form.Dashboard({
|
|
frm: this
|
|
});
|
|
|
|
this.states = new frappe.ui.form.States({
|
|
frm: this
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.email_doc = function (message) {
|
|
new frappe.views.CommunicationComposer({
|
|
doc: this.doc,
|
|
frm: this,
|
|
subject: __(this.meta.name) + ': ' + this.docname,
|
|
recipients: this.doc.email || this.doc.email_id || this.doc.contact_email,
|
|
attach_document_print: true,
|
|
message: message,
|
|
real_name: this.doc.real_name || this.doc.contact_display || this.doc.contact_name
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.rename_doc = function () {
|
|
frappe.model.rename_doc(this.doctype, this.docname);
|
|
};
|
|
|
|
_f.Frm.prototype.share_doc = function () {
|
|
this.shared.show();
|
|
};
|
|
|
|
_f.Frm.prototype.rename_notify = function (dt, old, name) {
|
|
if (this.meta.istable) return;
|
|
|
|
if (this.docname == old) this.docname = name;else return;
|
|
|
|
if (this && this.opendocs[old] && frappe.meta.docfield_copy[dt]) {
|
|
frappe.meta.docfield_copy[dt][name] = frappe.meta.docfield_copy[dt][old];
|
|
delete frappe.meta.docfield_copy[dt][old];
|
|
}
|
|
|
|
delete this.opendocs[old];
|
|
this.opendocs[name] = true;
|
|
|
|
if (this.meta.in_dialog || !this.in_form) {
|
|
return;
|
|
}
|
|
|
|
frappe.re_route[window.location.hash] = '#Form/' + encodeURIComponent(this.doctype) + '/' + encodeURIComponent(name);
|
|
frappe.set_route('Form', this.doctype, name);
|
|
};
|
|
|
|
_f.Frm.prototype.setup_meta = function (doctype) {
|
|
this.meta = frappe.get_doc('DocType', this.doctype);
|
|
this.perm = frappe.perm.get_perm(this.doctype);
|
|
if (this.meta.istable) {
|
|
this.meta.in_dialog = 1;
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.refresh_header = function (is_a_different_doc) {
|
|
if (!this.meta.in_dialog || this.in_form) {
|
|
frappe.utils.set_title(this.meta.issingle ? this.doctype : this.docname);
|
|
}
|
|
|
|
if (this.toolbar) {
|
|
if (is_a_different_doc) {
|
|
this.toolbar.current_status = undefined;
|
|
}
|
|
|
|
this.toolbar.refresh();
|
|
}
|
|
|
|
this.document_flow.refresh();
|
|
this.dashboard.refresh();
|
|
|
|
if (this.meta.is_submittable && this.perm[0] && this.perm[0].submit && !this.is_dirty() && !this.is_new() && this.doc.docstatus === 0) {
|
|
this.dashboard.add_comment(__('Submit this document to confirm'), 'alert-warning', true);
|
|
}
|
|
|
|
this.clear_custom_buttons();
|
|
|
|
this.show_web_link();
|
|
};
|
|
|
|
_f.Frm.prototype.show_web_link = function () {
|
|
var doc = this.doc,
|
|
me = this;
|
|
if (!doc.__islocal && doc.__onload && doc.__onload.is_website_generator) {
|
|
me.web_link && me.web_link.remove();
|
|
if (doc.__onload.published) {
|
|
me.add_web_link("/" + doc.route);
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.add_web_link = function (path) {
|
|
this.web_link = this.sidebar.add_user_action(__("See on Website"), function () {}).attr("href", path || this.doc.route).attr("target", "_blank");
|
|
};
|
|
|
|
_f.Frm.prototype.check_doc_perm = function () {
|
|
var dt = this.parent_doctype ? this.parent_doctype : this.doctype;
|
|
this.perm = frappe.perm.get_perm(dt, this.doc);
|
|
|
|
if (!this.perm[0].read) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
};
|
|
|
|
_f.Frm.prototype.refresh = function (docname) {
|
|
var is_a_different_doc = docname ? true : false;
|
|
|
|
if (docname) {
|
|
if (this.docname != docname && (!this.meta.in_dialog || this.in_form) && !this.meta.istable) {
|
|
frappe.utils.scroll_to(0);
|
|
this.hide_print();
|
|
}
|
|
frappe.ui.form.close_grid_form();
|
|
this.docname = docname;
|
|
}
|
|
|
|
cur_frm = this;
|
|
|
|
if (this.docname) {
|
|
this.doc = frappe.get_doc(this.doctype, this.docname);
|
|
|
|
if (!this.check_doc_perm()) {
|
|
frappe.show_not_permitted(__(this.doctype) + " " + __(this.docname));
|
|
return;
|
|
}
|
|
|
|
this.read_only = frappe.workflow.is_read_only(this.doctype, this.docname);
|
|
if (this.read_only) this.set_read_only(true);
|
|
|
|
if (!this.opendocs[this.docname]) {
|
|
this.check_doctype_conflict(this.docname);
|
|
} else {
|
|
if (this.doc && !this.doc.__unsaved && this.doc.__last_sync_on && new Date() - this.doc.__last_sync_on > this.refresh_if_stale_for * 1000) {
|
|
this.reload_doc();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!this.setup_done) {
|
|
this.setup();
|
|
}
|
|
|
|
this.cscript.is_onload = false;
|
|
if (!this.opendocs[this.docname]) {
|
|
var me = this;
|
|
this.cscript.is_onload = true;
|
|
this.setnewdoc();
|
|
$(document).trigger("form-load", [this]);
|
|
$(this.page.wrapper).on('hide', function (e) {
|
|
$(document).trigger("form-unload", [me]);
|
|
});
|
|
} else {
|
|
this.render_form(is_a_different_doc);
|
|
if (this.doc.localname) {
|
|
delete this.doc.localname;
|
|
$(document).trigger("form-rename", [this]);
|
|
}
|
|
}
|
|
|
|
if (this.print_preview.wrapper.is(":visible")) {
|
|
this.print_preview.preview();
|
|
}
|
|
|
|
if (is_a_different_doc) {
|
|
if (this.show_print_first && this.doc.docstatus === 1) {
|
|
this.print_doc();
|
|
}
|
|
}
|
|
|
|
this.$wrapper.removeClass('validated-form').toggleClass('editable-form', this.doc.docstatus === 0).toggleClass('submitted-form', this.doc.docstatus === 1).toggleClass('cancelled-form', this.doc.docstatus === 2);
|
|
|
|
this.show_if_needs_refresh();
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.show_if_needs_refresh = function () {
|
|
if (this.doc.__needs_refresh) {
|
|
if (this.doc.__unsaved) {
|
|
this.dashboard.set_headline_alert(__("This form has been modified after you have loaded it") + '<a class="btn btn-xs btn-primary pull-right" onclick="cur_frm.reload_doc()">' + __("Refresh") + '</a>', "alert-warning");
|
|
} else {
|
|
this.reload_doc();
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.render_form = function (is_a_different_doc) {
|
|
var _this = this;
|
|
|
|
if (!this.meta.istable) {
|
|
this.layout.doc = this.doc;
|
|
this.layout.attach_doc_and_docfields();
|
|
|
|
this.sidebar = new frappe.ui.form.Sidebar({
|
|
frm: this,
|
|
page: this.page
|
|
});
|
|
this.sidebar.make();
|
|
|
|
this.layout.show_message();
|
|
|
|
this.refresh_header(is_a_different_doc);
|
|
|
|
this.script_manager.trigger("refresh");
|
|
|
|
$(document).trigger('form_refresh', [this]);
|
|
|
|
this.refresh_fields();
|
|
|
|
if (this.cscript.is_onload) {
|
|
this.script_manager.trigger("onload_post_render");
|
|
}
|
|
|
|
frappe.timeout(0.1).then(function () {
|
|
return _this.dashboard.after_refresh();
|
|
});
|
|
|
|
if (this.is_new()) {
|
|
var first = this.form_wrapper.find('.form-layout input:first');
|
|
if (!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
|
|
first.focus();
|
|
}
|
|
}
|
|
} else {
|
|
this.refresh_header(is_a_different_doc);
|
|
}
|
|
|
|
this.$wrapper.trigger('render_complete');
|
|
|
|
if (!this.hidden) {
|
|
this.layout.show_empty_form_message();
|
|
}
|
|
|
|
this.scroll_to_element();
|
|
};
|
|
|
|
_f.Frm.prototype.refresh_field = function (fname) {
|
|
if (this.fields_dict[fname] && this.fields_dict[fname].refresh) {
|
|
this.fields_dict[fname].refresh();
|
|
this.layout.refresh_dependency();
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.refresh_fields = function () {
|
|
this.layout.refresh(this.doc);
|
|
this.layout.primary_button = this.$wrapper.find(".btn-primary");
|
|
|
|
this.cleanup_refresh(this);
|
|
};
|
|
|
|
_f.Frm.prototype.cleanup_refresh = function () {
|
|
var me = this;
|
|
if (me.fields_dict['amended_from']) {
|
|
if (me.doc.amended_from) {
|
|
unhide_field('amended_from');
|
|
if (me.fields_dict['amendment_date']) unhide_field('amendment_date');
|
|
} else {
|
|
hide_field('amended_from');
|
|
if (me.fields_dict['amendment_date']) hide_field('amendment_date');
|
|
}
|
|
}
|
|
|
|
if (me.fields_dict['trash_reason']) {
|
|
if (me.doc.trash_reason && me.doc.docstatus == 2) {
|
|
unhide_field('trash_reason');
|
|
} else {
|
|
hide_field('trash_reason');
|
|
}
|
|
}
|
|
|
|
if (me.meta.autoname && me.meta.autoname.substr(0, 6) == 'field:' && !me.doc.__islocal) {
|
|
var fn = me.meta.autoname.substr(6);
|
|
|
|
if (me.doc[fn]) {
|
|
me.toggle_display(fn, false);
|
|
}
|
|
}
|
|
|
|
if (me.meta.autoname == "naming_series:" && !me.doc.__islocal) {
|
|
me.toggle_display("naming_series", false);
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.setnewdoc = function () {
|
|
var me = this;
|
|
|
|
this.script_manager.trigger("before_load", this.doctype, this.docname).then(function () {
|
|
me.script_manager.trigger("onload");
|
|
me.opendocs[me.docname] = true;
|
|
me.render_form();
|
|
|
|
frappe.after_ajax(function () {
|
|
me.trigger_link_fields();
|
|
});
|
|
|
|
frappe.breadcrumbs.add(me.meta.module, me.doctype);
|
|
});
|
|
|
|
if (this.meta.track_seen) {
|
|
$('.list-id[data-name="' + me.docname + '"]').addClass('seen');
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.trigger_link_fields = function () {
|
|
if (this.is_new() && this.doc.__run_link_triggers) {
|
|
$.each(this.fields_dict, function (fieldname, field) {
|
|
if (field.df.fieldtype == "Link" && this.doc[fieldname]) {
|
|
field.set_value(this.doc[fieldname]);
|
|
}
|
|
});
|
|
|
|
delete this.doc.__run_link_triggers;
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.runscript = function (scriptname, callingfield, onrefresh) {
|
|
var me = this;
|
|
if (this.docname) {
|
|
if (callingfield) $(callingfield.input).set_working();
|
|
|
|
frappe.call({
|
|
method: "runserverobj",
|
|
args: { 'docs': this.doc, 'method': scriptname },
|
|
btn: callingfield.$input,
|
|
callback: function callback(r) {
|
|
if (!r.exc) {
|
|
if (onrefresh) {
|
|
onrefresh(r);
|
|
}
|
|
|
|
me.refresh_fields();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.copy_doc = function (onload, from_amend) {
|
|
this.validate_form_action("Create");
|
|
var newdoc = frappe.model.copy_doc(this.doc, from_amend);
|
|
|
|
newdoc.idx = null;
|
|
newdoc.__run_link_triggers = false;
|
|
if (onload) {
|
|
onload(newdoc);
|
|
}
|
|
frappe.set_route('Form', newdoc.doctype, newdoc.name);
|
|
};
|
|
|
|
_f.Frm.prototype.reload_doc = function () {
|
|
this.check_doctype_conflict(this.docname);
|
|
|
|
var me = this;
|
|
var onsave = function onsave(r, rtxt) {
|
|
me.refresh();
|
|
};
|
|
|
|
if (!me.doc.__islocal) {
|
|
frappe.model.remove_from_locals(me.doctype, me.docname);
|
|
frappe.model.with_doc(me.doctype, me.docname, function () {
|
|
me.refresh();
|
|
});
|
|
}
|
|
};
|
|
|
|
frappe.validated = 0;
|
|
|
|
Object.defineProperty(window, 'validated', {
|
|
get: function get() {
|
|
console.warn('Please use `frappe.validated` instead of `validated`. It will be deprecated soon.');
|
|
return frappe.validated;
|
|
},
|
|
set: function set(value) {
|
|
console.warn('Please use `frappe.validated` instead of `validated`. It will be deprecated soon.');
|
|
frappe.validated = value;
|
|
return frappe.validated;
|
|
}
|
|
});
|
|
|
|
_f.Frm.prototype.save = function (save_action, callback, btn, on_error) {
|
|
var me = this;
|
|
return new Promise(function (resolve) {
|
|
btn && $(btn).prop("disabled", true);
|
|
$(document.activeElement).blur();
|
|
|
|
frappe.ui.form.close_grid_form();
|
|
|
|
setTimeout(function () {
|
|
me._save(save_action, callback, btn, on_error, resolve);
|
|
}, 100);
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype._save = function (save_action, callback, btn, on_error, resolve) {
|
|
var _this2 = this;
|
|
|
|
var me = this;
|
|
if (!save_action) save_action = "Save";
|
|
this.validate_form_action(save_action, resolve);
|
|
|
|
if ((!this.meta.in_dialog || this.in_form) && !this.meta.istable) {
|
|
frappe.utils.scroll_to(0);
|
|
}
|
|
var after_save = function after_save(r) {
|
|
if (!r.exc) {
|
|
if (["Save", "Update", "Amend"].indexOf(save_action) !== -1) {
|
|
frappe.utils.play_sound("click");
|
|
}
|
|
|
|
me.script_manager.trigger("after_save");
|
|
me.refresh();
|
|
} else {
|
|
if (on_error) {
|
|
on_error();
|
|
}
|
|
}
|
|
callback && callback(r);
|
|
resolve();
|
|
};
|
|
|
|
if (save_action != "Update") {
|
|
frappe.validated = true;
|
|
frappe.run_serially([function () {
|
|
return _this2.script_manager.trigger("validate");
|
|
}, function () {
|
|
return _this2.script_manager.trigger("before_save");
|
|
}, function () {
|
|
if (!frappe.validated) {
|
|
btn && $(btn).prop("disabled", false);
|
|
if (on_error) {
|
|
on_error();
|
|
}
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
frappe.ui.form.save(me, save_action, after_save, btn);
|
|
}]);
|
|
} else {
|
|
frappe.ui.form.save(me, save_action, after_save, btn);
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.savesubmit = function (btn, callback, on_error) {
|
|
var me = this;
|
|
this.validate_form_action("Submit");
|
|
frappe.confirm(__("Permanently Submit {0}?", [this.docname]), function () {
|
|
frappe.validated = true;
|
|
me.script_manager.trigger("before_submit").then(function () {
|
|
if (!frappe.validated) {
|
|
if (on_error) on_error();
|
|
return;
|
|
}
|
|
|
|
return me.save('Submit', function (r) {
|
|
if (!r.exc) {
|
|
frappe.utils.play_sound("submit");
|
|
callback && callback();
|
|
me.script_manager.trigger("on_submit");
|
|
}
|
|
}, btn, on_error);
|
|
});
|
|
}, on_error);
|
|
};
|
|
|
|
_f.Frm.prototype.savecancel = function (btn, callback, on_error) {
|
|
var me = this;
|
|
this.validate_form_action('Cancel');
|
|
frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), function () {
|
|
frappe.validated = true;
|
|
me.script_manager.trigger("before_cancel").then(function () {
|
|
if (!frappe.validated) {
|
|
if (on_error) on_error();
|
|
return;
|
|
}
|
|
|
|
var after_cancel = function after_cancel(r) {
|
|
if (!r.exc) {
|
|
frappe.utils.play_sound("cancel");
|
|
me.refresh();
|
|
callback && callback();
|
|
me.script_manager.trigger("after_cancel");
|
|
} else {
|
|
on_error();
|
|
}
|
|
};
|
|
frappe.ui.form.save(me, "cancel", after_cancel, btn);
|
|
});
|
|
}, on_error);
|
|
};
|
|
|
|
_f.Frm.prototype.savetrash = function () {
|
|
this.validate_form_action("Delete");
|
|
frappe.model.delete_doc(this.doctype, this.docname, function (r) {
|
|
window.history.back();
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.amend_doc = function () {
|
|
if (!this.fields_dict['amended_from']) {
|
|
alert('"amended_from" field must be present to do an amendment.');
|
|
return;
|
|
}
|
|
this.validate_form_action("Amend");
|
|
var me = this;
|
|
var fn = function fn(newdoc) {
|
|
newdoc.amended_from = me.docname;
|
|
if (me.fields_dict && me.fields_dict['amendment_date']) newdoc.amendment_date = frappe.datetime.obj_to_str(new Date());
|
|
};
|
|
this.copy_doc(fn, 1);
|
|
frappe.utils.play_sound("click");
|
|
};
|
|
|
|
_f.Frm.prototype.disable_save = function () {
|
|
this.save_disabled = true;
|
|
this.toolbar.current_status = null;
|
|
this.page.clear_primary_action();
|
|
};
|
|
|
|
_f.Frm.prototype.enable_save = function () {
|
|
this.save_disabled = false;
|
|
this.toolbar.set_primary_action();
|
|
};
|
|
|
|
_f.Frm.prototype.save_or_update = function () {
|
|
if (this.save_disabled) return;
|
|
|
|
if (this.doc.docstatus === 0) {
|
|
this.save();
|
|
} else if (this.doc.docstatus === 1 && this.doc.__unsaved) {
|
|
this.save("Update");
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.dirty = function () {
|
|
this.doc.__unsaved = 1;
|
|
this.$wrapper.trigger('dirty');
|
|
};
|
|
|
|
_f.Frm.prototype.get_docinfo = function () {
|
|
return frappe.model.docinfo[this.doctype][this.docname];
|
|
};
|
|
|
|
_f.Frm.prototype.is_dirty = function () {
|
|
return this.doc.__unsaved;
|
|
};
|
|
|
|
_f.Frm.prototype.is_new = function () {
|
|
return this.doc.__islocal;
|
|
};
|
|
|
|
_f.Frm.prototype.reload_docinfo = function (_callback) {
|
|
var me = this;
|
|
frappe.call({
|
|
method: "frappe.desk.form.load.get_docinfo",
|
|
args: {
|
|
doctype: me.doctype,
|
|
name: me.doc.name
|
|
},
|
|
callback: function callback(r) {
|
|
if (_callback) _callback(r.docinfo);
|
|
me.timeline.refresh();
|
|
me.assign_to.refresh();
|
|
me.attachments.refresh();
|
|
}
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.get_perm = function (permlevel, access_type) {
|
|
return this.perm[permlevel] ? this.perm[permlevel][access_type] : null;
|
|
};
|
|
|
|
_f.Frm.prototype.set_intro = function (txt, append) {
|
|
this.dashboard.set_headline_alert(txt);
|
|
};
|
|
|
|
_f.Frm.prototype.set_footnote = function (txt) {
|
|
this.footnote_area = frappe.utils.set_footnote(this.footnote_area, this.body, txt);
|
|
};
|
|
|
|
_f.Frm.prototype.add_custom_button = function (label, fn, group) {
|
|
if (group && group.indexOf("fa fa-") !== -1) group = null;
|
|
var btn = this.page.add_inner_button(label, fn, group);
|
|
this.custom_buttons[label] = btn;
|
|
return btn;
|
|
};
|
|
|
|
_f.Frm.prototype.clear_custom_buttons = function () {
|
|
this.page.clear_inner_toolbar();
|
|
this.page.clear_user_actions();
|
|
this.custom_buttons = {};
|
|
};
|
|
|
|
_f.Frm.prototype.add_fetch = function (link_field, src_field, tar_field) {
|
|
if (!this.fetch_dict[link_field]) {
|
|
this.fetch_dict[link_field] = { 'columns': [], 'fields': [] };
|
|
}
|
|
this.fetch_dict[link_field].columns.push(src_field);
|
|
this.fetch_dict[link_field].fields.push(tar_field);
|
|
};
|
|
|
|
_f.Frm.prototype.set_print_heading = function (txt) {
|
|
this.pformat[this.docname] = txt;
|
|
};
|
|
|
|
_f.Frm.prototype.action_perm_type_map = {
|
|
"Create": "create",
|
|
"Save": "write",
|
|
"Submit": "submit",
|
|
"Update": "submit",
|
|
"Cancel": "cancel",
|
|
"Amend": "amend",
|
|
"Delete": "delete"
|
|
};
|
|
|
|
_f.Frm.prototype.validate_form_action = function (action, resolve) {
|
|
var perm_to_check = this.action_perm_type_map[action];
|
|
var allowed_for_workflow = false;
|
|
var perms = frappe.perm.get_perm(this.doc.doctype)[0];
|
|
|
|
if (frappe.workflow.is_read_only(this.doctype, this.docname) && (perms["write"] || perms["create"] || perms["submit"] || perms["cancel"])) {
|
|
var allowed_for_workflow = true;
|
|
}
|
|
|
|
if (!this.perm[0][perm_to_check] && !allowed_for_workflow) {
|
|
if (resolve) {
|
|
resolve();
|
|
}
|
|
frappe.throw(__("No permission to '{0}' {1}", [__(action), __(this.doc.doctype)]));
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.has_perm = function (ptype) {
|
|
return frappe.perm.has_perm(this.doctype, 0, ptype, this.doc);
|
|
};
|
|
|
|
_f.Frm.prototype.scroll_to_element = function () {
|
|
if (frappe.route_options && frappe.route_options.scroll_to) {
|
|
var scroll_to = frappe.route_options.scroll_to;
|
|
delete frappe.route_options.scroll_to;
|
|
|
|
var selector = [];
|
|
for (var key in scroll_to) {
|
|
var value = scroll_to[key];
|
|
selector.push(repl('[data-%(key)s="%(value)s"]', { key: key, value: value }));
|
|
}
|
|
|
|
selector = $(selector.join(" "));
|
|
if (selector.length) {
|
|
frappe.utils.scroll_to(selector);
|
|
}
|
|
}
|
|
};
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
window.get_server_fields = function (method, arg, table_field, doc, dt, dn, allow_edit, call_back) {
|
|
console.warn("This function 'get_server_fields' has been deprecated and will be removed soon.");
|
|
frappe.dom.freeze();
|
|
if ($.isPlainObject(arg)) arg = JSON.stringify(arg);
|
|
return $c('runserverobj', { 'method': method, 'docs': JSON.stringify(doc), 'arg': arg }, function (r, rt) {
|
|
frappe.dom.unfreeze();
|
|
if (r.message) {
|
|
var d = locals[dt][dn];
|
|
var field_dict = r.message;
|
|
for (var key in field_dict) {
|
|
d[key] = field_dict[key];
|
|
if (table_field) refresh_field(key, d.name, table_field);else refresh_field(key);
|
|
}
|
|
}
|
|
if (call_back) {
|
|
doc = locals[doc.doctype][doc.name];
|
|
call_back(doc, dt, dn);
|
|
}
|
|
});
|
|
};
|
|
|
|
window.set_multiple = function (dt, dn, dict, table_field) {
|
|
var d = locals[dt][dn];
|
|
for (var key in dict) {
|
|
d[key] = dict[key];
|
|
if (table_field) refresh_field(key, d.name, table_field);else refresh_field(key);
|
|
}
|
|
};
|
|
|
|
window.refresh_many = function (flist, dn, table_field) {
|
|
for (var i in flist) {
|
|
if (table_field) refresh_field(flist[i], dn, table_field);else refresh_field(flist[i]);
|
|
}
|
|
};
|
|
|
|
window.set_field_tip = function (n, txt) {
|
|
var df = frappe.meta.get_docfield(cur_frm.doctype, n, cur_frm.docname);
|
|
if (df) df.description = txt;
|
|
|
|
if (cur_frm && cur_frm.fields_dict) {
|
|
if (cur_frm.fields_dict[n]) cur_frm.fields_dict[n].comment_area.innerHTML = replace_newlines(txt);else console.log('[set_field_tip] Unable to set field tip: ' + n);
|
|
}
|
|
};
|
|
|
|
refresh_field = function refresh_field(n, docname, table_field) {
|
|
if ((typeof n === 'undefined' ? 'undefined' : _typeof(n)) == _typeof([])) refresh_many(n, docname, table_field);
|
|
|
|
if (n && typeof n === 'string' && table_field) {
|
|
var grid = cur_frm.fields_dict[table_field].grid,
|
|
field = frappe.utils.filter_dict(grid.docfields, { fieldname: n });
|
|
if (field && field.length) {
|
|
field = field[0];
|
|
var meta = frappe.meta.get_docfield(field.parent, field.fieldname, docname);
|
|
$.extend(field, meta);
|
|
if (docname) {
|
|
cur_frm.fields_dict[table_field].grid.grid_rows_by_docname[docname].refresh_field(n);
|
|
} else {
|
|
cur_frm.fields_dict[table_field].grid.refresh();
|
|
}
|
|
}
|
|
} else if (cur_frm) {
|
|
cur_frm.refresh_field(n);
|
|
}
|
|
};
|
|
|
|
window.set_field_options = function (n, txt) {
|
|
cur_frm.set_df_property(n, 'options', txt);
|
|
};
|
|
|
|
window.set_field_permlevel = function (n, level) {
|
|
cur_frm.set_df_property(n, 'permlevel', level);
|
|
};
|
|
|
|
toggle_field = function toggle_field(n, hidden) {
|
|
var df = frappe.meta.get_docfield(cur_frm.doctype, n, cur_frm.docname);
|
|
if (df) {
|
|
df.hidden = hidden;
|
|
refresh_field(n);
|
|
} else {
|
|
console.log((hidden ? "hide_field" : "unhide_field") + " cannot find field " + n);
|
|
}
|
|
};
|
|
|
|
hide_field = function hide_field(n) {
|
|
if (cur_frm) {
|
|
if (n.substr) toggle_field(n, 1);else {
|
|
for (var i in n) {
|
|
toggle_field(n[i], 1);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
unhide_field = function unhide_field(n) {
|
|
if (cur_frm) {
|
|
if (n.substr) toggle_field(n, 0);else {
|
|
for (var i in n) {
|
|
toggle_field(n[i], 0);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
get_field_obj = function get_field_obj(fn) {
|
|
return cur_frm.fields_dict[fn];
|
|
};
|
|
|
|
_f.Frm.prototype.get_doc = function () {
|
|
return locals[this.doctype][this.docname];
|
|
};
|
|
|
|
_f.Frm.prototype.set_currency_labels = function (fields_list, currency, parentfield) {
|
|
|
|
var me = this;
|
|
var doctype = parentfield ? this.fields_dict[parentfield].grid.doctype : this.doc.doctype;
|
|
var field_label_map = {};
|
|
var grid_field_label_map = {};
|
|
|
|
$.each(fields_list, function (i, fname) {
|
|
var docfield = frappe.meta.docfield_map[doctype][fname];
|
|
if (docfield) {
|
|
var label = __(docfield.label || "").replace(/\([^\)]*\)/g, "");
|
|
if (parentfield) {
|
|
grid_field_label_map[doctype + "-" + fname] = label.trim() + " (" + __(currency) + ")";
|
|
} else {
|
|
field_label_map[fname] = label.trim() + " (" + currency + ")";
|
|
}
|
|
}
|
|
});
|
|
|
|
$.each(field_label_map, function (fname, label) {
|
|
me.fields_dict[fname].set_label(label);
|
|
});
|
|
|
|
$.each(grid_field_label_map, function (fname, label) {
|
|
fname = fname.split("-");
|
|
var df = frappe.meta.get_docfield(fname[0], fname[1], me.doc.name);
|
|
if (df) df.label = label;
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.field_map = function (fnames, fn) {
|
|
if (typeof fnames === 'string') {
|
|
if (fnames == '*') {
|
|
fnames = Object.keys(this.fields_dict);
|
|
} else {
|
|
fnames = [fnames];
|
|
}
|
|
}
|
|
for (var i = 0, l = fnames.length; i < l; i++) {
|
|
var fieldname = fnames[i];
|
|
var field = frappe.meta.get_docfield(cur_frm.doctype, fieldname, cur_frm.docname);
|
|
if (field) {
|
|
fn(field);
|
|
cur_frm.refresh_field(fieldname);
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.get_docfield = function (fieldname1, fieldname2) {
|
|
if (fieldname2) {
|
|
var doctype = this.get_docfield(fieldname1).options;
|
|
return frappe.meta.get_docfield(doctype, fieldname2, this.docname);
|
|
} else {
|
|
return frappe.meta.get_docfield(this.doctype, fieldname1, this.docname);
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.set_df_property = function (fieldname, property, value, docname, table_field) {
|
|
if (!docname && !table_field) {
|
|
var df = this.get_docfield(fieldname);
|
|
} else {
|
|
var grid = cur_frm.fields_dict[table_field].grid,
|
|
fname = frappe.utils.filter_dict(grid.docfields, { 'fieldname': fieldname });
|
|
if (fname && fname.length) var df = frappe.meta.get_docfield(fname[0].parent, fieldname, docname);
|
|
}
|
|
if (df && df[property] != value) {
|
|
df[property] = value;
|
|
refresh_field(fieldname, table_field);
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.toggle_enable = function (fnames, enable) {
|
|
cur_frm.field_map(fnames, function (field) {
|
|
field.read_only = enable ? 0 : 1;
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.toggle_reqd = function (fnames, mandatory) {
|
|
cur_frm.field_map(fnames, function (field) {
|
|
field.reqd = mandatory ? true : false;
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.toggle_display = function (fnames, show) {
|
|
cur_frm.field_map(fnames, function (field) {
|
|
field.hidden = show ? 0 : 1;
|
|
});
|
|
};
|
|
|
|
_f.Frm.prototype.call_server = function (method, args, callback) {
|
|
return $c_obj(cur_frm.doc, method, args, callback);
|
|
};
|
|
|
|
_f.Frm.prototype.get_files = function () {
|
|
return cur_frm.attachments ? frappe.utils.sort(cur_frm.attachments.get_attachments(), "file_name", "string") : [];
|
|
};
|
|
|
|
_f.Frm.prototype.set_query = function (fieldname, opt1, opt2) {
|
|
if (opt2) {
|
|
this.fields_dict[opt1].grid.get_field(fieldname).get_query = opt2;
|
|
} else {
|
|
if (this.fields_dict[fieldname]) {
|
|
this.fields_dict[fieldname].get_query = opt1;
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.set_value_if_missing = function (field, value) {
|
|
this.set_value(field, value, true);
|
|
};
|
|
|
|
_f.Frm.prototype.clear_table = function (fieldname) {
|
|
frappe.model.clear_table(this.doc, fieldname);
|
|
};
|
|
|
|
_f.Frm.prototype.add_child = function (fieldname, values) {
|
|
var doc = frappe.model.add_child(this.doc, frappe.meta.get_docfield(this.doctype, fieldname).options, fieldname);
|
|
if (values) {
|
|
var d = {};
|
|
var unique_keys = ["idx", "name"];
|
|
|
|
Object.keys(values).map(function (key) {
|
|
if (!unique_keys.includes(key)) {
|
|
d[key] = values[key];
|
|
}
|
|
});
|
|
|
|
$.extend(doc, d);
|
|
}
|
|
return doc;
|
|
};
|
|
|
|
_f.Frm.prototype.set_value = function (field, value, if_missing) {
|
|
var me = this;
|
|
var _set = function _set(f, v) {
|
|
var fieldobj = me.fields_dict[f];
|
|
if (fieldobj) {
|
|
if (!if_missing || !frappe.model.has_value(me.doctype, me.doc.name, f)) {
|
|
if (fieldobj.df.fieldtype === "Table" && $.isArray(v)) {
|
|
|
|
frappe.model.clear_table(me.doc, fieldobj.df.fieldname);
|
|
|
|
for (var i = 0, j = v.length; i < j; i++) {
|
|
var d = v[i];
|
|
var child = frappe.model.add_child(me.doc, fieldobj.df.options, fieldobj.df.fieldname, i + 1);
|
|
$.extend(child, d);
|
|
}
|
|
|
|
me.refresh_field(f);
|
|
return Promise.resolve();
|
|
} else {
|
|
return frappe.model.set_value(me.doctype, me.doc.name, f, v);
|
|
}
|
|
}
|
|
} else {
|
|
frappe.msgprint(__("Field {0} not found.", [f]));
|
|
throw "frm.set_value";
|
|
}
|
|
};
|
|
|
|
if (typeof field == "string") {
|
|
return _set(field, value);
|
|
} else if ($.isPlainObject(field)) {
|
|
var tasks = [];
|
|
|
|
var _loop = function _loop(f) {
|
|
var v = field[f];
|
|
if (me.get_field(f)) {
|
|
tasks.push(function () {
|
|
return _set(f, v);
|
|
});
|
|
}
|
|
};
|
|
|
|
for (var f in field) {
|
|
_loop(f);
|
|
}
|
|
return frappe.run_serially(tasks);
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.call = function (opts, args, callback) {
|
|
var me = this;
|
|
if (typeof opts === 'string') {
|
|
opts = {
|
|
method: opts,
|
|
doc: this.doc,
|
|
args: args,
|
|
callback: callback
|
|
};
|
|
}
|
|
if (!opts.doc) {
|
|
if (opts.method.indexOf(".") === -1) opts.method = frappe.model.get_server_module_name(me.doctype) + "." + opts.method;
|
|
opts.original_callback = opts.callback;
|
|
opts.callback = function (r) {
|
|
if ($.isPlainObject(r.message)) {
|
|
if (opts.child) {
|
|
opts.child = locals[opts.child.doctype][opts.child.name];
|
|
|
|
var std_field_list = ["doctype"].concat(frappe.model.std_fields_list);
|
|
for (var key in r.message) {
|
|
if (std_field_list.indexOf(key) === -1) {
|
|
opts.child[key] = r.message[key];
|
|
}
|
|
}
|
|
|
|
me.fields_dict[opts.child.parentfield].refresh();
|
|
} else {
|
|
me.set_value(r.message);
|
|
}
|
|
}
|
|
opts.original_callback && opts.original_callback(r);
|
|
};
|
|
} else {
|
|
opts.original_callback = opts.callback;
|
|
opts.callback = function (r) {
|
|
if (!r.exc) me.refresh_fields();
|
|
|
|
opts.original_callback && opts.original_callback(r);
|
|
};
|
|
}
|
|
return frappe.call(opts);
|
|
};
|
|
|
|
_f.Frm.prototype.get_field = function (field) {
|
|
return cur_frm.fields_dict[field];
|
|
};
|
|
|
|
_f.Frm.prototype.set_read_only = function () {
|
|
var perm = [];
|
|
var docperms = frappe.perm.get_perm(cur_frm.doc.doctype);
|
|
for (var i = 0, l = docperms.length; i < l; i++) {
|
|
var p = docperms[i];
|
|
perm[p.permlevel || 0] = { read: 1, print: 1, cancel: 1 };
|
|
}
|
|
cur_frm.perm = perm;
|
|
};
|
|
|
|
_f.Frm.prototype.trigger = function (event) {
|
|
return this.script_manager.trigger(event);
|
|
};
|
|
|
|
_f.Frm.prototype.get_formatted = function (fieldname) {
|
|
return frappe.format(this.doc[fieldname], frappe.meta.get_docfield(this.doctype, fieldname, this.docname), { no_icon: true }, this.doc);
|
|
};
|
|
|
|
_f.Frm.prototype.open_grid_row = function () {
|
|
return frappe.ui.form.get_open_grid_form();
|
|
};
|
|
|
|
_f.Frm.prototype.is_new = function () {
|
|
return this.doc.__islocal;
|
|
};
|
|
|
|
_f.Frm.prototype.get_title = function () {
|
|
if (this.meta.title_field) {
|
|
return this.doc[this.meta.title_field];
|
|
} else {
|
|
return this.doc.name;
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.get_selected = function () {
|
|
var selected = {},
|
|
me = this;
|
|
frappe.meta.get_table_fields(this.doctype).forEach(function (df) {
|
|
var _selected = me.fields_dict[df.fieldname].grid.get_selected();
|
|
if (_selected.length) {
|
|
selected[df.fieldname] = _selected;
|
|
}
|
|
});
|
|
return selected;
|
|
};
|
|
|
|
_f.Frm.prototype.has_mapper = function () {
|
|
if (this._has_mapper === undefined) {
|
|
this._has_mapper = this.meta.__js && this.meta.__js.search('open_mapped_doc') !== -1 ? true : false;
|
|
}
|
|
return this._has_mapper;
|
|
};
|
|
|
|
_f.Frm.prototype.set_indicator_formatter = function (fieldname, get_color, get_text) {
|
|
var doctype;
|
|
if (frappe.meta.docfield_map[this.doctype][fieldname]) {
|
|
doctype = this.doctype;
|
|
} else {
|
|
frappe.meta.get_table_fields(this.doctype).every(function (df) {
|
|
if (frappe.meta.docfield_map[df.options][fieldname]) {
|
|
doctype = df.options;
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
frappe.meta.get_docfield(doctype, fieldname, this.doc.name).formatter = function (value, df, options, doc) {
|
|
if (value) {
|
|
return repl('<a class="indicator %(color)s" href="#Form/%(doctype)s/%(name)s">%(label)s</a>', {
|
|
color: get_color(doc),
|
|
doctype: df.options,
|
|
name: value,
|
|
label: get_text ? get_text(doc) : value
|
|
});
|
|
} else {
|
|
return '';
|
|
}
|
|
};
|
|
};
|
|
|
|
_f.Frm.prototype.can_create = function (doctype) {
|
|
if (!frappe.model.can_create(doctype)) {
|
|
return false;
|
|
}
|
|
|
|
if (this.custom_make_buttons && this.custom_make_buttons[doctype]) {
|
|
return !!this.custom_buttons[this.custom_make_buttons[doctype]];
|
|
}
|
|
|
|
if (this.can_make_methods && this.can_make_methods[doctype]) {
|
|
return this.can_make_methods[doctype](this);
|
|
} else {
|
|
if (this.meta.is_submittable && !this.doc.docstatus == 1) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.make_new = function (doctype) {
|
|
var me = this;
|
|
if (this.make_methods && this.make_methods[doctype]) {
|
|
return this.make_methods[doctype](this);
|
|
} else if (this.custom_make_buttons && this.custom_make_buttons[doctype]) {
|
|
this.custom_buttons[this.custom_make_buttons[doctype]].trigger('click');
|
|
} else {
|
|
frappe.model.with_doctype(doctype, function () {
|
|
var new_doc = frappe.model.get_new_doc(doctype);
|
|
|
|
frappe.get_meta(doctype).fields.forEach(function (df) {
|
|
if (df.fieldtype === 'Link' && df.options === me.doctype) {
|
|
new_doc[df.fieldname] = me.doc.name;
|
|
}
|
|
});
|
|
|
|
frappe.set_route('Form', doctype, new_doc.name);
|
|
});
|
|
}
|
|
};
|
|
|
|
_f.Frm.prototype.update_in_all_rows = function (table_fieldname, fieldname, value) {
|
|
if (!value) return;
|
|
var cl = this.doc[table_fieldname] || [];
|
|
for (var i = 0; i < cl.length; i++) {
|
|
if (!cl[i][fieldname]) cl[i][fieldname] = value;
|
|
}
|
|
refresh_field("items");
|
|
};
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
frappe.ui.form.Toolbar = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.refresh();
|
|
this.add_update_button_on_dirty();
|
|
this.setup_editable_title();
|
|
},
|
|
refresh: function refresh() {
|
|
this.make_menu();
|
|
this.set_title();
|
|
this.page.clear_user_actions();
|
|
this.show_title_as_dirty();
|
|
this.set_primary_action();
|
|
|
|
if (this.frm.meta.hide_toolbar) {
|
|
this.page.hide_menu();
|
|
} else {
|
|
if (this.frm.doc.__islocal) {
|
|
this.page.hide_menu();
|
|
this.print_icon && this.print_icon.addClass("hide");
|
|
} else {
|
|
this.page.show_menu();
|
|
this.print_icon && this.print_icon.removeClass("hide");
|
|
}
|
|
}
|
|
},
|
|
set_title: function set_title() {
|
|
if (this.frm.meta.title_field) {
|
|
var title = strip_html((this.frm.doc[this.frm.meta.title_field] || "").trim() || this.frm.docname);
|
|
if (this.frm.doc.__islocal || title === this.frm.docname || this.frm.meta.autoname === "hash") {
|
|
this.page.set_title_sub("");
|
|
} else {
|
|
this.page.set_title_sub(this.frm.docname);
|
|
}
|
|
} else {
|
|
var title = this.frm.docname;
|
|
}
|
|
|
|
var me = this;
|
|
title = __(title);
|
|
this.page.set_title(title);
|
|
if (this.frm.meta.title_field) {
|
|
frappe.utils.set_title(title + " - " + this.frm.docname);
|
|
}
|
|
this.page.$title_area.toggleClass("editable-title", !!(this.is_title_editable() || this.can_rename()));
|
|
|
|
this.set_indicator();
|
|
},
|
|
is_title_editable: function is_title_editable() {
|
|
if (this.frm.meta.title_field === "title" && this.frm.perm[0].write && !this.frm.get_docfield("title").options) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
can_rename: function can_rename() {
|
|
return this.frm.perm[0].write && this.frm.meta.allow_rename;
|
|
},
|
|
setup_editable_title: function setup_editable_title() {
|
|
var me = this;
|
|
this.page.$title_area.find(".title-text").on("click", function () {
|
|
if (me.is_title_editable()) {
|
|
frappe.prompt({ fieldname: "title", fieldtype: "Data",
|
|
label: __("Title"), reqd: 1, "default": me.frm.doc.title }, function (data) {
|
|
if (data.title) {
|
|
me.frm.set_value("title", data.title);
|
|
if (!me.frm.doc.__islocal) {
|
|
me.frm.save_or_update();
|
|
} else {
|
|
me.set_title();
|
|
}
|
|
}
|
|
}, __("Edit Title"), __("Update"));
|
|
}
|
|
if (me.can_rename()) {
|
|
me.frm.rename_doc();
|
|
}
|
|
});
|
|
},
|
|
get_dropdown_menu: function get_dropdown_menu(label) {
|
|
return this.page.add_dropdown(label);
|
|
},
|
|
set_indicator: function set_indicator() {
|
|
if (this.frm.save_disabled) return;
|
|
|
|
var indicator = frappe.get_indicator(this.frm.doc);
|
|
if (indicator) {
|
|
this.page.set_indicator(indicator[0], indicator[1]);
|
|
} else {
|
|
this.page.clear_indicator();
|
|
}
|
|
},
|
|
make_menu: function make_menu() {
|
|
this.page.clear_icons();
|
|
this.page.clear_menu();
|
|
var me = this;
|
|
var p = this.frm.perm[0];
|
|
var docstatus = cint(this.frm.doc.docstatus);
|
|
var is_submittable = frappe.model.is_submittable(this.frm.doc.doctype);
|
|
|
|
var print_settings = frappe.model.get_doc(":Print Settings", "Print Settings");
|
|
var allow_print_for_draft = cint(print_settings.allow_print_for_draft);
|
|
var allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled);
|
|
|
|
if (!is_submittable || docstatus == 1 || allow_print_for_cancelled && docstatus == 2 || allow_print_for_draft && docstatus == 0) {
|
|
if (frappe.model.can_print(null, me.frm)) {
|
|
this.page.add_menu_item(__("Print"), function () {
|
|
me.frm.print_doc();
|
|
}, true);
|
|
this.print_icon = this.page.add_action_icon("fa fa-print", function () {
|
|
me.frm.print_doc();
|
|
});
|
|
}
|
|
}
|
|
|
|
if (frappe.model.can_email(null, me.frm) && me.frm.doc.docstatus < 2) {
|
|
this.page.add_menu_item(__("Email"), function () {
|
|
me.frm.email_doc();
|
|
}, true);
|
|
}
|
|
|
|
if (!me.frm.meta.issingle) {
|
|
this.page.add_menu_item(__('Links'), function () {
|
|
me.show_linked_with();
|
|
}, true);
|
|
}
|
|
|
|
if (in_list(frappe.boot.user.can_create, me.frm.doctype) && !me.frm.meta.allow_copy) {
|
|
this.page.add_menu_item(__("Duplicate"), function () {
|
|
me.frm.copy_doc();
|
|
}, true);
|
|
}
|
|
|
|
if (this.can_rename()) {
|
|
this.page.add_menu_item(__("Rename"), function () {
|
|
me.frm.rename_doc();
|
|
}, true);
|
|
}
|
|
|
|
this.page.add_menu_item(__("Reload"), function () {
|
|
me.frm.reload_doc();
|
|
}, true);
|
|
|
|
if (cint(me.frm.doc.docstatus) != 1 && !me.frm.doc.__islocal && frappe.model.can_delete(me.frm.doctype)) {
|
|
this.page.add_menu_item(__("Delete"), function () {
|
|
me.frm.savetrash();
|
|
}, true);
|
|
}
|
|
|
|
if (frappe.user_roles.includes("System Manager")) {
|
|
this.page.add_menu_item(__("Customize"), function () {
|
|
frappe.set_route("Form", "Customize Form", {
|
|
doc_type: me.frm.doctype
|
|
});
|
|
}, true);
|
|
|
|
if (frappe.boot.developer_mode === 1 && me.frm.meta.issingle) {
|
|
this.page.add_menu_item(__("Edit DocType"), function () {
|
|
frappe.set_route('Form', 'DocType', me.frm.doctype);
|
|
}, true);
|
|
}
|
|
}
|
|
|
|
if (!this.frm.doc.__unsaved) {
|
|
if (is_submittable && docstatus == 1) {
|
|
this.page.add_menu_item(__("Request Feedback"), function () {
|
|
var feedback = new frappe.utils.Feedback();
|
|
feedback.manual_feedback_request(me.frm.doc);
|
|
}, true);
|
|
}
|
|
}
|
|
|
|
if (p[CREATE] && !this.frm.meta.issingle) {
|
|
this.page.add_menu_item(__("New {0} (Ctrl+B)", [__(me.frm.doctype)]), function () {
|
|
frappe.new_doc(me.frm.doctype, true);
|
|
}, true);
|
|
}
|
|
},
|
|
can_save: function can_save() {
|
|
return this.get_docstatus() === 0;
|
|
},
|
|
can_submit: function can_submit() {
|
|
return this.get_docstatus() === 0 && !this.frm.doc.__islocal && !this.frm.doc.__unsaved && this.frm.perm[0].submit && !this.has_workflow();
|
|
},
|
|
can_update: function can_update() {
|
|
return this.get_docstatus() === 1 && !this.frm.doc.__islocal && this.frm.perm[0].submit && this.frm.doc.__unsaved;
|
|
},
|
|
can_cancel: function can_cancel() {
|
|
return this.get_docstatus() === 1 && this.frm.perm[0].cancel && !this.read_only && !this.has_workflow();
|
|
},
|
|
can_amend: function can_amend() {
|
|
return this.get_docstatus() === 2 && this.frm.perm[0].amend && !this.read_only;
|
|
},
|
|
has_workflow: function has_workflow() {
|
|
if (this._has_workflow === undefined) this._has_workflow = frappe.get_list("Workflow", { document_type: this.frm.doctype }).length;
|
|
return this._has_workflow;
|
|
},
|
|
get_docstatus: function get_docstatus() {
|
|
return cint(this.frm.doc.docstatus);
|
|
},
|
|
show_linked_with: function show_linked_with() {
|
|
if (!this.frm.linked_with) {
|
|
this.frm.linked_with = new frappe.ui.form.LinkedWith({
|
|
frm: this.frm
|
|
});
|
|
}
|
|
this.frm.linked_with.show();
|
|
},
|
|
set_primary_action: function set_primary_action(dirty) {
|
|
if (!dirty) {
|
|
this.page.clear_user_actions();
|
|
}
|
|
|
|
var status = this.get_action_status();
|
|
if (status) {
|
|
if (status !== this.current_status) {
|
|
this.set_page_actions(status);
|
|
}
|
|
} else {
|
|
this.page.clear_actions();
|
|
this.current_status = null;
|
|
}
|
|
},
|
|
get_action_status: function get_action_status() {
|
|
var status = null;
|
|
if (this.frm.page.current_view_name === 'print' || this.frm.hidden) {
|
|
status = "Edit";
|
|
} else if (this.can_submit()) {
|
|
status = "Submit";
|
|
} else if (this.can_save()) {
|
|
if (!this.frm.save_disabled) {
|
|
status = "Save";
|
|
}
|
|
} else if (this.can_update()) {
|
|
status = "Update";
|
|
} else if (this.can_cancel()) {
|
|
status = "Cancel";
|
|
} else if (this.can_amend()) {
|
|
status = "Amend";
|
|
}
|
|
return status;
|
|
},
|
|
set_page_actions: function set_page_actions(status) {
|
|
var me = this;
|
|
this.page.clear_actions();
|
|
|
|
if (status !== 'Edit') {
|
|
var perm_to_check = this.frm.action_perm_type_map[status];
|
|
if (!this.frm.perm[0][perm_to_check]) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (status === "Edit") {
|
|
this.page.set_primary_action(__("Edit"), function () {
|
|
me.frm.page.set_view('main');
|
|
}, 'octicon octicon-pencil');
|
|
} else if (status === "Cancel") {
|
|
this.page.set_secondary_action(__(status), function () {
|
|
me.frm.savecancel(this);
|
|
}, "octicon octicon-circle-slash");
|
|
} else {
|
|
var click = {
|
|
"Save": function Save() {
|
|
return me.frm.save('Save', null, this);
|
|
},
|
|
"Submit": function Submit() {
|
|
return me.frm.savesubmit(this);
|
|
},
|
|
"Update": function Update() {
|
|
return me.frm.save('Update', null, this);
|
|
},
|
|
"Amend": function Amend() {
|
|
return me.frm.amend_doc();
|
|
}
|
|
}[status];
|
|
|
|
var icon = {
|
|
"Save": "octicon octicon-check",
|
|
"Submit": "octicon octicon-lock",
|
|
"Update": "octicon octicon-check",
|
|
"Amend": "octicon octicon-split"
|
|
}[status];
|
|
|
|
this.page.set_primary_action(__(status), click, icon);
|
|
}
|
|
|
|
this.current_status = status;
|
|
},
|
|
make_cancel_amend_button: function make_cancel_amend_button() {
|
|
var me = this;
|
|
var docstatus = cint(this.frm.doc.docstatus);
|
|
var p = this.frm.perm[0];
|
|
var has_workflow = this.has_workflow();
|
|
|
|
if (has_workflow) {
|
|
return;
|
|
} else if (docstatus == 1 && p[CANCEL]) {
|
|
this.page.set_secondary_action(__('Cancel'), function () {
|
|
me.frm.savecancel(this);
|
|
}, 'fa fa-ban-circle');
|
|
} else if (docstatus == 2 && p[AMEND]) {
|
|
this.page.set_secondary_action(__('Amend'), function () {
|
|
me.frm.amend_doc();
|
|
}, 'fa fa-pencil', true);
|
|
}
|
|
},
|
|
add_update_button_on_dirty: function add_update_button_on_dirty() {
|
|
var me = this;
|
|
$(this.frm.wrapper).on("dirty", function () {
|
|
me.show_title_as_dirty();
|
|
|
|
me.frm.page.clear_actions_menu();
|
|
|
|
if (!me.frm.save_disabled) {
|
|
me.set_primary_action(true);
|
|
}
|
|
});
|
|
},
|
|
show_title_as_dirty: function show_title_as_dirty() {
|
|
if (this.frm.save_disabled) return;
|
|
|
|
if (this.frm.doc.__unsaved) {
|
|
this.page.set_indicator(__("Not Saved"), "orange");
|
|
}
|
|
|
|
$(this.frm.wrapper).attr("data-state", this.frm.doc.__unsaved ? "dirty" : "clean");
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.Dashboard = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.section = this.frm.fields_dict._form_dashboard.wrapper;
|
|
this.parent = this.section.find('.section-body');
|
|
this.wrapper = $(frappe.render_template('form_dashboard', { frm: this.frm })).appendTo(this.parent);
|
|
|
|
this.progress_area = this.wrapper.find(".progress-area");
|
|
this.heatmap_area = this.wrapper.find('.form-heatmap');
|
|
this.graph_area = this.wrapper.find('.form-graph');
|
|
this.stats_area = this.wrapper.find('.form-stats');
|
|
this.stats_area_row = this.stats_area.find('.row');
|
|
this.links_area = this.wrapper.find('.form-links');
|
|
this.transactions_area = this.links_area.find('.transactions');
|
|
},
|
|
reset: function reset() {
|
|
this.section.addClass('hidden');
|
|
this.clear_headline();
|
|
|
|
this.progress_area.empty().addClass('hidden');
|
|
|
|
this.links_area.addClass('hidden');
|
|
this.links_area.find('.count, .open-notification').addClass('hidden');
|
|
|
|
this.stats_area.addClass('hidden');
|
|
this.stats_area_row.empty();
|
|
|
|
this.wrapper.find('.custom').remove();
|
|
},
|
|
set_headline: function set_headline(html) {
|
|
this.frm.layout.show_message(html);
|
|
},
|
|
clear_headline: function clear_headline() {
|
|
this.frm.layout.show_message();
|
|
},
|
|
|
|
add_comment: function add_comment(text, alert_class, permanent) {
|
|
var me = this;
|
|
this.set_headline_alert(text, alert_class);
|
|
if (!permanent) {
|
|
setTimeout(function () {
|
|
me.clear_headline();
|
|
}, 10000);
|
|
}
|
|
},
|
|
|
|
clear_comment: function clear_comment() {
|
|
this.clear_headline();
|
|
},
|
|
|
|
set_headline_alert: function set_headline_alert(text, indicator_color) {
|
|
if (!indicator_color) {
|
|
indicator_color = 'orange';
|
|
}
|
|
if (text) {
|
|
this.set_headline('<div><span class="indicator ' + indicator_color + '">' + text + '</span></div>');
|
|
} else {
|
|
this.clear_headline();
|
|
}
|
|
},
|
|
|
|
add_section: function add_section(html) {
|
|
return $('<div class="form-dashboard-section custom">' + html + '</div>').appendTo(this.wrapper);
|
|
},
|
|
|
|
add_progress: function add_progress(title, percent, message) {
|
|
var progress_chart = this.make_progress_chart(title);
|
|
|
|
if (!$.isArray(percent)) {
|
|
percent = this.format_percent(title, percent);
|
|
}
|
|
|
|
var progress = $('<div class="progress"></div>').appendTo(progress_chart);
|
|
$.each(percent, function (i, opts) {
|
|
$(repl('<div class="progress-bar %(progress_class)s" style="width: %(width)s" \
|
|
title="%(title)s"></div>', opts)).appendTo(progress);
|
|
});
|
|
|
|
if (message) {
|
|
$('<p class="text-muted small">' + message + '</p>').appendTo(this.progress_area);
|
|
}
|
|
|
|
this.show();
|
|
},
|
|
|
|
format_percent: function format_percent(title, percent) {
|
|
var width = cint(percent) < 1 ? 1 : cint(percent);
|
|
var progress_class = "";
|
|
if (width < 10) progress_class = "progress-bar-danger";
|
|
if (width > 99.9) progress_class = "progress-bar-success";
|
|
|
|
return [{
|
|
title: title,
|
|
width: width + '%',
|
|
progress_class: progress_class
|
|
}];
|
|
},
|
|
make_progress_chart: function make_progress_chart(title) {
|
|
var progress_chart = $('<div class="progress-chart" title="' + (title || '') + '"></div>').appendTo(this.progress_area.removeClass('hidden'));
|
|
return progress_chart;
|
|
},
|
|
|
|
refresh: function refresh() {
|
|
this.reset();
|
|
if (this.frm.doc.__islocal) {
|
|
return;
|
|
}
|
|
|
|
if (!this.data) {
|
|
this.init_data();
|
|
}
|
|
|
|
var show = false;
|
|
|
|
if (this.data && (this.data.transactions || []).length) {
|
|
if (this.data.docstatus && this.frm.doc.docstatus !== this.data.docstatus) {
|
|
return;
|
|
}
|
|
this.render_links();
|
|
this.set_open_count();
|
|
show = true;
|
|
}
|
|
|
|
if (this.data.heatmap) {
|
|
this.render_heatmap();
|
|
show = true;
|
|
}
|
|
|
|
if (this.data.graph) {
|
|
this.setup_graph();
|
|
show = true;
|
|
}
|
|
|
|
if (show) {
|
|
this.show();
|
|
}
|
|
},
|
|
|
|
after_refresh: function after_refresh() {
|
|
var me = this;
|
|
|
|
this.links_area.find('.btn-new').each(function () {
|
|
if (me.frm.can_create($(this).attr('data-doctype'))) {
|
|
$(this).removeClass('hidden');
|
|
}
|
|
});
|
|
},
|
|
|
|
init_data: function init_data() {
|
|
this.data = this.frm.meta.__dashboard || {};
|
|
if (!this.data.transactions) this.data.transactions = [];
|
|
if (!this.data.internal_links) this.data.internal_links = {};
|
|
this.filter_permissions();
|
|
},
|
|
|
|
filter_permissions: function filter_permissions() {
|
|
var transactions = [];
|
|
(this.data.transactions || []).forEach(function (group) {
|
|
var items = [];
|
|
group.items.forEach(function (doctype) {
|
|
if (frappe.model.can_read(doctype)) {
|
|
items.push(doctype);
|
|
}
|
|
});
|
|
|
|
if (items.length) {
|
|
group.items = items;
|
|
transactions.push(group);
|
|
}
|
|
});
|
|
this.data.transactions = transactions;
|
|
},
|
|
render_links: function render_links() {
|
|
var me = this;
|
|
this.links_area.removeClass('hidden');
|
|
this.links_area.find('.btn-new').addClass('hidden');
|
|
if (this.data_rendered) {
|
|
return;
|
|
}
|
|
|
|
this.data.frm = this.frm;
|
|
|
|
$(frappe.render_template('form_links', this.data)).appendTo(this.transactions_area);
|
|
|
|
this.transactions_area.find(".badge-link").on('click', function () {
|
|
me.open_document_list($(this).parent());
|
|
});
|
|
|
|
this.transactions_area.find('.open-notification').on('click', function () {
|
|
me.open_document_list($(this).parent(), true);
|
|
});
|
|
|
|
this.transactions_area.find('.btn-new').on('click', function () {
|
|
me.frm.make_new($(this).attr('data-doctype'));
|
|
});
|
|
|
|
this.data_rendered = true;
|
|
},
|
|
open_document_list: function open_document_list($link, show_open) {
|
|
var doctype = $link.attr('data-doctype'),
|
|
names = $link.attr('data-names') || [];
|
|
|
|
if (this.data.internal_links[doctype]) {
|
|
if (names.length) {
|
|
frappe.route_options = { 'name': ['in', names] };
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
frappe.route_options = this.get_document_filter(doctype);
|
|
if (show_open) {
|
|
$.extend(frappe.route_options, frappe.ui.notifications.get_filters(doctype));
|
|
}
|
|
}
|
|
|
|
frappe.set_route("List", doctype);
|
|
},
|
|
get_document_filter: function get_document_filter(doctype) {
|
|
var filter = {};
|
|
var fieldname = this.data.non_standard_fieldnames ? this.data.non_standard_fieldnames[doctype] || this.data.fieldname : this.data.fieldname;
|
|
filter[fieldname] = this.frm.doc.name;
|
|
return filter;
|
|
},
|
|
set_open_count: function set_open_count() {
|
|
if (!this.data.transactions) {
|
|
return;
|
|
}
|
|
|
|
var items = [],
|
|
me = this;
|
|
|
|
this.data.transactions.forEach(function (group) {
|
|
group.items.forEach(function (item) {
|
|
items.push(item);
|
|
});
|
|
});
|
|
|
|
var method = this.data.method || 'frappe.desk.notifications.get_open_count';
|
|
|
|
frappe.call({
|
|
type: "GET",
|
|
method: method,
|
|
args: {
|
|
doctype: this.frm.doctype,
|
|
name: this.frm.doc.name
|
|
},
|
|
callback: function callback(r) {
|
|
if (r.message.timeline_data) {
|
|
me.update_heatmap(r.message.timeline_data);
|
|
}
|
|
|
|
$.each(r.message.count, function (i, d) {
|
|
me.frm.dashboard.set_badge_count(d.name, cint(d.open_count), cint(d.count));
|
|
});
|
|
|
|
$.each(me.data.internal_links, function (doctype, link) {
|
|
var table_fieldname = link[0],
|
|
link_fieldname = link[1];
|
|
var names = [];
|
|
(me.frm.doc[table_fieldname] || []).forEach(function (d) {
|
|
var value = d[link_fieldname];
|
|
if (value && names.indexOf(value) === -1) {
|
|
names.push(value);
|
|
}
|
|
});
|
|
me.frm.dashboard.set_badge_count(doctype, 0, names.length, names);
|
|
});
|
|
|
|
me.frm.dashboard_data = r.message;
|
|
me.frm.trigger('dashboard_update');
|
|
}
|
|
});
|
|
},
|
|
set_badge_count: function set_badge_count(doctype, open_count, count, names) {
|
|
var $link = $(this.transactions_area).find('.document-link[data-doctype="' + doctype + '"]');
|
|
|
|
if (open_count) {
|
|
$link.find('.open-notification').removeClass('hidden').html(open_count > 99 ? '99+' : open_count);
|
|
}
|
|
|
|
if (count) {
|
|
$link.find('.count').removeClass('hidden').html(count > 99 ? '99+' : count);
|
|
}
|
|
|
|
if (this.data.internal_links[doctype]) {
|
|
if (names && names.length) {
|
|
$link.attr('data-names', names ? names.join(',') : '');
|
|
} else {
|
|
$link.find('a').attr('disabled', true);
|
|
}
|
|
}
|
|
},
|
|
|
|
update_heatmap: function update_heatmap(data) {
|
|
if (this.heatmap) {
|
|
this.heatmap.update(data);
|
|
}
|
|
},
|
|
|
|
render_heatmap: function render_heatmap() {
|
|
if (!this.heatmap) {
|
|
this.heatmap = new CalHeatMap();
|
|
this.heatmap.init({
|
|
itemSelector: "#heatmap-" + frappe.model.scrub(this.frm.doctype),
|
|
domain: "month",
|
|
subDomain: "day",
|
|
start: moment().subtract(1, 'year').add(1, 'month').toDate(),
|
|
cellSize: 9,
|
|
cellPadding: 2,
|
|
domainGutter: 2,
|
|
range: 12,
|
|
domainLabelFormat: function domainLabelFormat(date) {
|
|
return moment(date).format("MMM").toUpperCase();
|
|
},
|
|
displayLegend: false,
|
|
legend: [5, 10, 15, 20]
|
|
});
|
|
|
|
this.heatmap_area.removeClass('hidden').find('svg').css({ 'margin': 'auto' });
|
|
|
|
var heatmap_message = this.heatmap_area.find('.heatmap-message');
|
|
if (this.data.heatmap_message) {
|
|
heatmap_message.removeClass('hidden').html(this.data.heatmap_message);
|
|
} else {
|
|
heatmap_message.addClass('hidden');
|
|
}
|
|
}
|
|
},
|
|
|
|
add_indicator: function add_indicator(label, color) {
|
|
this.show();
|
|
this.stats_area.removeClass('hidden');
|
|
|
|
var indicators = this.stats_area_row.find('.indicator-column');
|
|
var n_indicators = indicators.length + 1;
|
|
var colspan;
|
|
if (n_indicators > 4) {
|
|
colspan = 3;
|
|
} else {
|
|
colspan = 12 / n_indicators;
|
|
}
|
|
|
|
if (indicators.length) {
|
|
indicators.removeClass().addClass('col-sm-' + colspan).addClass('indicator-column');
|
|
}
|
|
|
|
var indicator = $('<div class="col-sm-' + colspan + ' indicator-column"><span class="indicator ' + color + '">' + label + '</span></div>').appendTo(this.stats_area_row);
|
|
|
|
return indicator;
|
|
},
|
|
|
|
setup_graph: function setup_graph() {
|
|
var me = this;
|
|
|
|
var method = this.data.graph_method;
|
|
var args = {
|
|
doctype: this.frm.doctype,
|
|
docname: this.frm.doc.name
|
|
};
|
|
|
|
$.extend(args, this.data.graph_method_args);
|
|
|
|
frappe.call({
|
|
type: "GET",
|
|
method: method,
|
|
args: args,
|
|
|
|
callback: function callback(r) {
|
|
if (r.message) {
|
|
me.render_graph(r.message);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
render_graph: function render_graph(args) {
|
|
var me = this;
|
|
this.graph_area.empty().removeClass('hidden');
|
|
$.extend(args, {
|
|
parent: me.graph_area,
|
|
mode: 'line',
|
|
height: 140
|
|
});
|
|
|
|
new frappe.ui.Graph(args);
|
|
},
|
|
|
|
setup_chart: function setup_chart(opts) {
|
|
var me = this;
|
|
|
|
this.graph_area.removeClass('hidden');
|
|
|
|
$.extend(opts, {
|
|
wrapper: me.graph_area,
|
|
padding: {
|
|
right: 30,
|
|
bottom: 30
|
|
}
|
|
});
|
|
|
|
this.chart = new frappe.ui.Chart(opts);
|
|
if (this.chart) {
|
|
this.show();
|
|
this.chart.set_chart_size(me.wrapper.width() - 60);
|
|
}
|
|
},
|
|
show: function show() {
|
|
this.section.removeClass('hidden');
|
|
}
|
|
});
|
|
|
|
frappe.provide('frappe.document_flow');
|
|
|
|
frappe.ui.form.DocumentFlow = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
|
|
this.module = frappe.get_meta(this.frm.doctype).module;
|
|
if (!frappe.document_flow || !frappe.document_flow[this.module]) {
|
|
return;
|
|
}
|
|
this.doctypes = frappe.document_flow[this.module][this.frm.doctype];
|
|
if (!this.doctypes) {
|
|
return;
|
|
}
|
|
|
|
this.wrapper = $('<div class="document-flow-wrapper hidden"></div>').prependTo(this.frm.layout.wrapper);
|
|
},
|
|
|
|
refresh: function refresh() {
|
|
if (this.doctypes) {
|
|
this.reset();
|
|
this.render();
|
|
}
|
|
},
|
|
|
|
reset: function reset() {
|
|
this.wrapper.empty().addClass('hidden');
|
|
this.linked_with = {};
|
|
},
|
|
|
|
render: function render() {
|
|
var me = this;
|
|
|
|
$(frappe.render_template('form_document_flow', {
|
|
frm: this.frm,
|
|
doctypes: this.doctypes
|
|
})).appendTo(this.wrapper.removeClass('hidden'));
|
|
|
|
this.wrapper.on('click', '.document-flow-link', function () {
|
|
var doctype = $(this).attr("data-doctype");
|
|
if (me.frm.doctype != doctype) {
|
|
me.get_linked_docs(doctype);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (!this.frm.doc.__islocal) {
|
|
this.mark_completed_flow();
|
|
}
|
|
},
|
|
|
|
get_linked_docs: function get_linked_docs(for_doctype) {
|
|
if (!this.linked_with[for_doctype]) {
|
|
this.linked_with[for_doctype] = new frappe.ui.form.LinkedWith({
|
|
frm: this.frm,
|
|
for_doctype: for_doctype
|
|
});
|
|
}
|
|
|
|
this.linked_with[for_doctype].show();
|
|
},
|
|
|
|
mark_completed_flow: function mark_completed_flow() {
|
|
var me = this;
|
|
frappe.call({
|
|
method: "frappe.desk.form.document_flow.get_document_completion_status",
|
|
args: {
|
|
doctypes: me.doctypes,
|
|
frm_doctype: me.frm.doctype,
|
|
frm_docname: me.frm.docname
|
|
},
|
|
callback: function callback(r) {
|
|
if (!r.message) {
|
|
return;
|
|
}
|
|
$.each(me.doctypes, function (i, doctype) {
|
|
if (r.message[doctype] && me.frm.doctype != doctype) {
|
|
me.wrapper.find("[data-doctype='" + doctype + "']a .indicator").removeClass("darkgrey").addClass("black");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.save = function (frm, action, _callback, btn) {
|
|
$(btn).prop("disabled", true);
|
|
|
|
var working_label = {
|
|
"Save": __("Saving"),
|
|
"Submit": __("Submitting"),
|
|
"Update": __("Updating"),
|
|
"Amend": __("Amending"),
|
|
"Cancel": __("Cancelling")
|
|
}[toTitle(action)];
|
|
|
|
var freeze_message = working_label ? __(working_label) : "";
|
|
|
|
var save = function save() {
|
|
check_name(function () {
|
|
$(frm.wrapper).addClass('validated-form');
|
|
if (check_mandatory()) {
|
|
_call({
|
|
method: "frappe.desk.form.save.savedocs",
|
|
args: { doc: frm.doc, action: action },
|
|
callback: function callback(r) {
|
|
$(document).trigger("save", [frm.doc]);
|
|
_callback(r);
|
|
},
|
|
btn: btn,
|
|
freeze_message: freeze_message
|
|
});
|
|
} else {
|
|
$(btn).prop("disabled", false);
|
|
}
|
|
});
|
|
};
|
|
|
|
var cancel = function cancel() {
|
|
var args = {
|
|
doctype: frm.doc.doctype,
|
|
name: frm.doc.name
|
|
};
|
|
|
|
var workflow_state_fieldname = frappe.workflow.get_state_fieldname(frm.doctype);
|
|
if (workflow_state_fieldname) {
|
|
$.extend(args, {
|
|
workflow_state_fieldname: workflow_state_fieldname,
|
|
workflow_state: frm.doc[workflow_state_fieldname]
|
|
|
|
});
|
|
}
|
|
|
|
_call({
|
|
method: "frappe.desk.form.save.cancel",
|
|
args: args,
|
|
callback: function callback(r) {
|
|
$(document).trigger("save", [frm.doc]);
|
|
_callback(r);
|
|
},
|
|
btn: btn,
|
|
freeze_message: freeze_message
|
|
});
|
|
};
|
|
|
|
var check_name = function check_name(callback) {
|
|
var doc = frm.doc;
|
|
var meta = locals.DocType[doc.doctype];
|
|
if (doc.__islocal && meta && meta.autoname && meta.autoname.toLowerCase() == 'prompt') {
|
|
var d = frappe.prompt(__("Name"), function (values) {
|
|
var newname = values.value;
|
|
if (newname) {
|
|
doc.__newname = strip(newname);
|
|
} else {
|
|
frappe.msgprint(__("Name is required"));
|
|
throw "name required";
|
|
}
|
|
|
|
callback();
|
|
}, __('Enter the name of the new {0}', [doc.doctype]), __("Create"));
|
|
|
|
if (doc.__newname) {
|
|
d.set_value("value", doc.__newname);
|
|
}
|
|
|
|
d.onhide = function () {
|
|
$(btn).prop("disabled", false);
|
|
};
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
var check_mandatory = function check_mandatory() {
|
|
var me = this;
|
|
var has_errors = false;
|
|
frm.scroll_set = false;
|
|
|
|
if (frm.doc.docstatus == 2) return true;
|
|
|
|
$.each(frappe.model.get_all_docs(frm.doc), function (i, doc) {
|
|
var error_fields = [];
|
|
var folded = false;
|
|
|
|
$.each(frappe.meta.docfield_list[doc.doctype] || [], function (i, docfield) {
|
|
if (docfield.fieldname) {
|
|
var df = frappe.meta.get_docfield(doc.doctype, docfield.fieldname, frm.doc.name);
|
|
|
|
if (df.fieldtype === "Fold") {
|
|
folded = frm.layout.folded;
|
|
}
|
|
|
|
if (df.reqd && !frappe.model.has_value(doc.doctype, doc.name, df.fieldname)) {
|
|
has_errors = true;
|
|
error_fields[error_fields.length] = __(df.label);
|
|
|
|
if (!me.scroll_set) {
|
|
scroll_to(doc.parentfield || df.fieldname);
|
|
}
|
|
|
|
if (folded) {
|
|
frm.layout.unfold();
|
|
folded = false;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (error_fields.length) {
|
|
if (doc.parenttype) {
|
|
var message = __('Mandatory fields required in table {0}, Row {1}', [__(frappe.meta.docfield_map[doc.parenttype][doc.parentfield].label).bold(), doc.idx]);
|
|
} else {
|
|
var message = __('Mandatory fields required in {0}', [__(doc.doctype)]);
|
|
}
|
|
message = message + '<br><br><ul><li>' + error_fields.join('</li><li>') + "</ul>";
|
|
frappe.msgprint({
|
|
message: message,
|
|
indicator: 'red',
|
|
title: __('Missing Fields')
|
|
});
|
|
}
|
|
});
|
|
|
|
return !has_errors;
|
|
};
|
|
|
|
var scroll_to = function scroll_to(fieldname) {
|
|
var f = cur_frm.fields_dict[fieldname];
|
|
if (f) {
|
|
$(document).scrollTop($(f.wrapper).offset().top - 60);
|
|
}
|
|
frm.scroll_set = true;
|
|
};
|
|
|
|
var _call = function _call(opts) {
|
|
|
|
if (frappe.ui.form.is_saving) {
|
|
console.log("Already saving. Please wait a few moments.");
|
|
throw "saving";
|
|
}
|
|
|
|
frappe.ui.form.remove_old_form_route();
|
|
frappe.ui.form.is_saving = true;
|
|
|
|
return frappe.call({
|
|
freeze: true,
|
|
freeze_message: opts.freeze_message,
|
|
method: opts.method,
|
|
args: opts.args,
|
|
btn: opts.btn,
|
|
callback: function callback(r) {
|
|
opts.callback && opts.callback(r);
|
|
},
|
|
always: function always(r) {
|
|
$(btn).prop("disabled", false);
|
|
frappe.ui.form.is_saving = false;
|
|
if (r) {
|
|
var doc = r.docs && r.docs[0];
|
|
if (doc) {
|
|
frappe.ui.form.update_calling_link(doc);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
if (action === "cancel") {
|
|
cancel();
|
|
} else {
|
|
save();
|
|
}
|
|
};
|
|
|
|
frappe.ui.form.remove_old_form_route = function () {
|
|
var index = -1;
|
|
var current_route = frappe.get_route();
|
|
frappe.route_history.map(function (arr, i) {
|
|
if (arr.join("/") === current_route.join("/")) {
|
|
index = i;
|
|
}
|
|
});
|
|
frappe.route_history.splice(index, 1);
|
|
};
|
|
|
|
frappe.ui.form.update_calling_link = function (newdoc) {
|
|
if (frappe._from_link && newdoc.doctype === frappe._from_link.df.options) {
|
|
var doc = frappe.get_doc(frappe._from_link.doctype, frappe._from_link.docname);
|
|
|
|
if (doc && doc.parentfield) {
|
|
$.each(frappe._from_link.frm.fields_dict[doc.parentfield].grid.grid_rows, function (index, field) {
|
|
if (field.doc && field.doc.name === frappe._from_link.docname) {
|
|
frappe._from_link.set_value(newdoc.name);
|
|
}
|
|
});
|
|
} else {
|
|
frappe._from_link.set_value(newdoc.name);
|
|
}
|
|
|
|
frappe._from_link.refresh();
|
|
|
|
if (frappe._from_link.frm) {
|
|
frappe.set_route("Form", frappe._from_link.frm.doctype, frappe._from_link.frm.docname).then(function () {
|
|
frappe.utils.scroll_to(frappe._from_link_scrollY);
|
|
});
|
|
}
|
|
|
|
frappe._from_link = null;
|
|
}
|
|
};
|
|
|
|
frappe.provide("frappe.ui.form.handlers");
|
|
|
|
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 add_handler(fieldname, handler) {
|
|
var handler_list = frappe.ui.form.get_event_handler_list(doctype, fieldname);
|
|
handler_list.push(handler);
|
|
|
|
if (cur_frm && cur_frm.doctype === doctype) {
|
|
cur_frm.events[fieldname] = handler;
|
|
}
|
|
};
|
|
|
|
if (!handler && $.isPlainObject(fieldname)) {
|
|
for (var key in fieldname) {
|
|
var fn = fieldname[key];
|
|
if (typeof fn === "function") {
|
|
add_handler(key, fn);
|
|
}
|
|
}
|
|
} else {
|
|
add_handler(fieldname, handler);
|
|
}
|
|
};
|
|
|
|
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.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
},
|
|
make: function make(ControllerClass) {
|
|
this.frm.cscript = $.extend(this.frm.cscript, new ControllerClass({ frm: this.frm }));
|
|
},
|
|
trigger: function trigger(event_name, doctype, name) {
|
|
var me = this;
|
|
doctype = doctype || this.frm.doctype;
|
|
name = name || this.frm.docname;
|
|
|
|
var tasks = [];
|
|
var handlers = this.get_handlers(event_name, doctype);
|
|
|
|
this.frm.selected_doc = frappe.get_doc(doctype, name);
|
|
|
|
var runner = function runner(_function, is_old_style) {
|
|
var _promise = null;
|
|
if (is_old_style) {
|
|
_promise = me.frm.cscript[_function](me.frm.doc, doctype, name);
|
|
} else {
|
|
_promise = _function(me.frm, doctype, name);
|
|
}
|
|
|
|
if (_promise && _promise.then) {
|
|
return _promise;
|
|
} else {
|
|
return frappe.after_server_call();
|
|
}
|
|
};
|
|
|
|
handlers.new_style.forEach(function (_function) {
|
|
if (event_name === 'setup') {
|
|
runner(_function, false);
|
|
} else {
|
|
tasks.push(function () {
|
|
return runner(_function, false);
|
|
});
|
|
}
|
|
});
|
|
|
|
handlers.old_style.forEach(function (_function) {
|
|
if (event_name === 'setup') {
|
|
runner(_function, true);
|
|
} else {
|
|
tasks.push(function () {
|
|
return runner(_function, true);
|
|
});
|
|
}
|
|
});
|
|
|
|
return frappe.run_serially(tasks);
|
|
},
|
|
has_handlers: function has_handlers(event_name, doctype) {
|
|
var handlers = this.get_handlers(event_name, doctype);
|
|
return handlers && (handlers.old_style.length || handlers.new_style.length);
|
|
},
|
|
get_handlers: function get_handlers(event_name, doctype) {
|
|
var me = this;
|
|
var 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 (this.frm.cscript[event_name]) {
|
|
handlers.old_style.push(event_name);
|
|
}
|
|
if (this.frm.cscript["custom_" + event_name]) {
|
|
handlers.old_style.push("custom_" + event_name);
|
|
}
|
|
return handlers;
|
|
},
|
|
setup: function setup() {
|
|
var doctype = this.frm.meta;
|
|
var me = this;
|
|
|
|
var cs = doctype.__js;
|
|
if (cs) {
|
|
var tmp = eval(cs);
|
|
}
|
|
|
|
if (doctype.__custom_js) {
|
|
try {
|
|
eval(doctype.__custom_js);
|
|
} catch (e) {
|
|
frappe.msgprint({
|
|
title: __('Error in Custom Script'),
|
|
indicator: 'orange',
|
|
message: '<pre class="small"><code>' + e.stack + '</code></pre>'
|
|
});
|
|
}
|
|
}
|
|
|
|
function setup_add_fetch(df) {
|
|
if ((['Data', 'Read Only', 'Text', 'Small Text', 'Text Editor', 'Code'].includes(df.fieldtype) || df.read_only == 1) && df.options && df.options.indexOf(".") != -1) {
|
|
var parts = df.options.split(".");
|
|
me.frm.add_fetch(parts[0], parts[1], df.fieldname);
|
|
}
|
|
}
|
|
|
|
$.each(this.frm.fields, function (i, field) {
|
|
setup_add_fetch(field.df);
|
|
if (field.df.fieldtype === "Table") {
|
|
$.each(frappe.meta.get_docfields(field.df.options, me.frm.docname), function (i, df) {
|
|
setup_add_fetch(df);
|
|
});
|
|
}
|
|
});
|
|
|
|
doctype.__css && frappe.dom.set_style(doctype.__css);
|
|
|
|
this.trigger('setup');
|
|
},
|
|
log_error: function log_error(caller, e) {
|
|
frappe.show_alert("Error in Client Script.");
|
|
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: function 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]);
|
|
});
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.get_open_grid_form = function () {
|
|
return $(".grid-row-open").data("grid_row");
|
|
};
|
|
|
|
frappe.ui.form.close_grid_form = function () {
|
|
var open_form = frappe.ui.form.get_open_grid_form();
|
|
open_form && open_form.hide_form();
|
|
|
|
if (frappe.ui.form.editable_row) {
|
|
frappe.ui.form.editable_row.toggle_editable_row(false);
|
|
}
|
|
};
|
|
|
|
frappe.ui.form.Grid = Class.extend({
|
|
init: function init(opts) {
|
|
var me = this;
|
|
$.extend(this, opts);
|
|
this.fieldinfo = {};
|
|
this.doctype = this.df.options;
|
|
|
|
if (this.doctype) {
|
|
this.meta = frappe.get_meta(this.doctype);
|
|
}
|
|
this.fields_map = {};
|
|
this.template = null;
|
|
this.multiple_set = false;
|
|
if (this.frm && this.frm.meta.__form_grid_templates && this.frm.meta.__form_grid_templates[this.df.fieldname]) {
|
|
this.template = this.frm.meta.__form_grid_templates[this.df.fieldname];
|
|
}
|
|
|
|
this.is_grid = true;
|
|
},
|
|
|
|
allow_on_grid_editing: function allow_on_grid_editing() {
|
|
if (frappe.utils.is_xs()) {
|
|
return false;
|
|
} else if (this.meta && this.meta.editable_grid || !this.meta) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
make: function make() {
|
|
var me = this;
|
|
|
|
this.wrapper = $(frappe.render_template("grid_body", {})).appendTo(this.parent).attr("data-fieldname", this.df.fieldname);
|
|
|
|
this.form_grid = this.wrapper.find('.form-grid');
|
|
|
|
this.wrapper.find(".grid-add-row").click(function () {
|
|
me.add_new_row(null, null, true);
|
|
me.set_focus_on_row();
|
|
return false;
|
|
});
|
|
|
|
this.custom_buttons = {};
|
|
this.grid_buttons = this.wrapper.find('.grid-buttons');
|
|
this.remove_rows_button = this.grid_buttons.find('.grid-remove-rows');
|
|
|
|
this.setup_allow_bulk_edit();
|
|
this.setup_check();
|
|
if (this.df.on_setup) {
|
|
this.df.on_setup(this);
|
|
}
|
|
},
|
|
setup_check: function setup_check() {
|
|
var me = this;
|
|
this.wrapper.on('click', '.grid-row-check', function (e) {
|
|
var $check = $(this);
|
|
if ($check.parents('.grid-heading-row:first').length !== 0) {
|
|
var checked = $check.prop('checked');
|
|
$check.parents('.form-grid:first').find('.grid-row-check').prop('checked', checked);
|
|
|
|
(me.grid_rows || []).forEach(function (row) {
|
|
row.doc.__checked = checked ? 1 : 0;
|
|
});
|
|
} else {
|
|
var docname = $check.parents('.grid-row:first').attr('data-name');
|
|
me.grid_rows_by_docname[docname].select($check.prop('checked'));
|
|
}
|
|
me.refresh_remove_rows_button();
|
|
});
|
|
|
|
this.remove_rows_button.on('click', function () {
|
|
var dirty = false;
|
|
|
|
me.get_selected().forEach(function (docname) {
|
|
me.grid_rows_by_docname[docname].remove();
|
|
dirty = true;
|
|
});
|
|
if (dirty) {
|
|
setTimeout(function () {
|
|
me.refresh();
|
|
}, 100);
|
|
}
|
|
});
|
|
},
|
|
select_row: function select_row(name) {
|
|
this.grid_rows_by_docname[name].select();
|
|
},
|
|
remove_all: function remove_all() {
|
|
this.grid_rows.forEach(function (row) {
|
|
row.remove();
|
|
});
|
|
},
|
|
refresh_remove_rows_button: function refresh_remove_rows_button() {
|
|
this.remove_rows_button.toggleClass('hide', this.wrapper.find('.grid-body .grid-row-check:checked:first').length ? false : true);
|
|
},
|
|
get_selected: function get_selected() {
|
|
return (this.grid_rows || []).map(function (row) {
|
|
return row.doc.__checked ? row.doc.name : null;
|
|
}).filter(function (d) {
|
|
return d;
|
|
});
|
|
},
|
|
get_selected_children: function get_selected_children() {
|
|
return (this.grid_rows || []).map(function (row) {
|
|
return row.doc.__checked ? row.doc : null;
|
|
}).filter(function (d) {
|
|
return d;
|
|
});
|
|
},
|
|
make_head: function make_head() {
|
|
if (!this.header_row) {
|
|
this.header_row = new frappe.ui.form.GridRow({
|
|
parent: $(this.parent).find(".grid-heading-row"),
|
|
parent_df: this.df,
|
|
docfields: this.docfields,
|
|
frm: this.frm,
|
|
grid: this
|
|
});
|
|
}
|
|
},
|
|
refresh: function refresh(force) {
|
|
!this.wrapper && this.make();
|
|
var me = this,
|
|
$rows = $(me.parent).find(".rows"),
|
|
data = this.get_data();
|
|
|
|
this.setup_fields();
|
|
|
|
if (this.frm) {
|
|
this.display_status = frappe.perm.get_field_display_status(this.df, this.frm.doc, this.perm);
|
|
} else {
|
|
this.display_status = 'Write';
|
|
}
|
|
|
|
if (this.display_status === "None") return;
|
|
|
|
if (!force && this.data_rows_are_same(data)) {
|
|
this.header_row && this.header_row.refresh();
|
|
for (var i in this.grid_rows) {
|
|
this.grid_rows[i].refresh();
|
|
}
|
|
} else {
|
|
var _scroll_y = $(document).scrollTop();
|
|
|
|
this.make_head();
|
|
|
|
if (!this.grid_rows) {
|
|
this.grid_rows = [];
|
|
}
|
|
|
|
this.truncate_rows(data);
|
|
this.grid_rows_by_docname = {};
|
|
|
|
for (var ri = 0; ri < data.length; ri++) {
|
|
var d = data[ri];
|
|
|
|
if (d.idx === undefined) {
|
|
d.idx = ri + 1;
|
|
}
|
|
|
|
if (this.grid_rows[ri]) {
|
|
var grid_row = this.grid_rows[ri];
|
|
grid_row.doc = d;
|
|
grid_row.refresh();
|
|
} else {
|
|
var grid_row = new frappe.ui.form.GridRow({
|
|
parent: $rows,
|
|
parent_df: this.df,
|
|
docfields: this.docfields,
|
|
doc: d,
|
|
frm: this.frm,
|
|
grid: this
|
|
});
|
|
this.grid_rows.push(grid_row);
|
|
}
|
|
|
|
this.grid_rows_by_docname[d.name] = grid_row;
|
|
}
|
|
|
|
this.wrapper.find(".grid-empty").toggleClass("hide", !!data.length);
|
|
|
|
this.setup_toolbar();
|
|
|
|
if (this.frm && this.is_sortable() && !this.sortable_setup_done) {
|
|
this.make_sortable($rows);
|
|
this.sortable_setup_done = true;
|
|
}
|
|
|
|
this.last_display_status = this.display_status;
|
|
this.last_docname = this.frm && this.frm.docname;
|
|
frappe.utils.scroll_to(_scroll_y);
|
|
}
|
|
|
|
this.form_grid.toggleClass('error', !!(this.df.reqd && !(data && data.length)));
|
|
|
|
this.refresh_remove_rows_button();
|
|
|
|
this.wrapper.trigger('change');
|
|
},
|
|
setup_toolbar: function setup_toolbar() {
|
|
if (this.is_editable()) {
|
|
this.wrapper.find(".grid-footer").toggle(true);
|
|
|
|
if (this.cannot_add_rows) {
|
|
this.wrapper.find(".grid-add-row, .grid-add-multiple-rows").addClass('hide');
|
|
} else {
|
|
this.wrapper.find(".grid-add-row").removeClass('hide');
|
|
|
|
if (this.multiple_set) {
|
|
this.wrapper.find(".grid-add-multiple-rows").removeClass('hide');
|
|
}
|
|
}
|
|
} else {
|
|
this.wrapper.find(".grid-footer").toggle(false);
|
|
}
|
|
},
|
|
truncate_rows: function truncate_rows(data) {
|
|
if (this.grid_rows.length > data.length) {
|
|
for (var i = data.length; i < this.grid_rows.length; i++) {
|
|
var grid_row = this.grid_rows[i];
|
|
grid_row.wrapper.remove();
|
|
}
|
|
this.grid_rows.splice(data.length);
|
|
}
|
|
},
|
|
setup_fields: function setup_fields() {
|
|
var me = this;
|
|
|
|
if (this.frm && this.frm.docname) {
|
|
this.df = frappe.meta.get_docfield(this.frm.doctype, this.df.fieldname, this.frm.docname);
|
|
} else {
|
|
if (this.df.options) {
|
|
this.df = frappe.meta.get_docfield(this.df.options, this.df.fieldname);
|
|
}
|
|
}
|
|
|
|
if (this.doctype) {
|
|
this.docfields = frappe.meta.get_docfields(this.doctype, this.frm.docname);
|
|
} else {
|
|
this.docfields = this.df.fields;
|
|
}
|
|
|
|
this.docfields.forEach(function (df) {
|
|
me.fields_map[df.fieldname] = df;
|
|
});
|
|
},
|
|
refresh_row: function refresh_row(docname) {
|
|
this.grid_rows_by_docname[docname] && this.grid_rows_by_docname[docname].refresh();
|
|
},
|
|
data_rows_are_same: function data_rows_are_same(data) {
|
|
if (this.grid_rows) {
|
|
var same = data.length == this.grid_rows.length && this.display_status == this.last_display_status && this.frm && this.frm.docname == this.last_docname && !$.map(this.grid_rows, function (g, i) {
|
|
return g && g.doc && g.doc.name == data[i].name ? null : true;
|
|
}).length;
|
|
|
|
return same;
|
|
}
|
|
},
|
|
make_sortable: function make_sortable($rows) {
|
|
var me = this;
|
|
if ('ontouchstart' in window) {
|
|
return;
|
|
}
|
|
|
|
new Sortable($rows.get(0), {
|
|
group: { name: 'row' },
|
|
handle: '.sortable-handle',
|
|
draggable: '.grid-row',
|
|
filter: 'li, a',
|
|
onUpdate: function onUpdate(event, ui) {
|
|
me.frm.doc[me.df.fieldname] = [];
|
|
$rows.find(".grid-row").each(function (i, item) {
|
|
var doc = locals[me.doctype][$(item).attr('data-name')];
|
|
doc.idx = i + 1;
|
|
me.frm.doc[me.df.fieldname].push(doc);
|
|
});
|
|
|
|
me.grid_rows = [];
|
|
me.frm.doc[me.df.fieldname].forEach(function (d) {
|
|
me.grid_rows.push(me.grid_rows_by_docname[d.name]);
|
|
});
|
|
me.frm.script_manager.trigger(me.df.fieldname + "_move", me.df.options, me.frm.doc[me.df.fieldname][event.newIndex].name);
|
|
me.refresh();
|
|
|
|
me.frm.dirty();
|
|
}
|
|
});
|
|
|
|
$(this.frm.wrapper).trigger("grid-make-sortable", [this.frm]);
|
|
},
|
|
get_data: function get_data() {
|
|
var data = this.frm ? this.frm.doc[this.df.fieldname] || [] : this.df.get_data();
|
|
data.sort(function (a, b) {
|
|
return a.idx - b.idx;
|
|
});
|
|
return data;
|
|
},
|
|
set_column_disp: function set_column_disp(fieldname, show) {
|
|
if ($.isArray(fieldname)) {
|
|
var me = this;
|
|
for (var i = 0, l = fieldname.length; i < l; i++) {
|
|
var fname = fieldname[i];
|
|
me.get_docfield(fname).hidden = show ? 0 : 1;
|
|
}
|
|
} else {
|
|
this.get_docfield(fieldname).hidden = show ? 0 : 1;
|
|
}
|
|
|
|
this.refresh(true);
|
|
},
|
|
toggle_reqd: function toggle_reqd(fieldname, reqd) {
|
|
this.get_docfield(fieldname).reqd = reqd;
|
|
this.refresh();
|
|
},
|
|
toggle_enable: function toggle_enable(fieldname, enable) {
|
|
this.get_docfield(fieldname).read_only = enable ? 0 : 1;
|
|
this.refresh();
|
|
},
|
|
toggle_display: function toggle_display(fieldname, show) {
|
|
this.get_docfield(fieldname).hidden = show ? 0 : 1;
|
|
this.refresh();
|
|
},
|
|
get_docfield: function get_docfield(fieldname) {
|
|
return frappe.meta.get_docfield(this.doctype, fieldname, this.frm ? this.frm.docname : null);
|
|
},
|
|
get_row: function get_row(key) {
|
|
if (typeof key == 'number') {
|
|
if (key < 0) {
|
|
return this.grid_rows[this.grid_rows.length + key];
|
|
} else {
|
|
return this.grid_rows[key];
|
|
}
|
|
} else {
|
|
return this.grid_rows_by_docname[key];
|
|
}
|
|
},
|
|
get_grid_row: function get_grid_row(key) {
|
|
return this.get_row(key);
|
|
},
|
|
get_field: function get_field(fieldname) {
|
|
if (!this.fieldinfo[fieldname]) this.fieldinfo[fieldname] = {};
|
|
return this.fieldinfo[fieldname];
|
|
},
|
|
set_value: function set_value(fieldname, value, doc) {
|
|
if (this.display_status !== "None" && this.grid_rows_by_docname[doc.name]) {
|
|
this.grid_rows_by_docname[doc.name].refresh_field(fieldname, value);
|
|
}
|
|
},
|
|
add_new_row: function add_new_row(idx, callback, show) {
|
|
if (this.is_editable()) {
|
|
if (this.frm) {
|
|
var d = frappe.model.add_child(this.frm.doc, this.df.options, this.df.fieldname, idx);
|
|
d.__unedited = true;
|
|
this.frm.script_manager.trigger(this.df.fieldname + "_add", d.doctype, d.name);
|
|
this.refresh();
|
|
} else {
|
|
this.df.data.push({ name: "batch " + (this.df.data.length + 1), idx: this.df.data.length + 1 });
|
|
this.refresh();
|
|
}
|
|
|
|
if (show) {
|
|
if (idx) {
|
|
this.wrapper.find("[data-idx='" + idx + "']").data("grid_row").toggle_view(true, callback);
|
|
} else {
|
|
if (!this.allow_on_grid_editing()) {
|
|
this.wrapper.find(".grid-row:last").data("grid_row").toggle_view(true, callback);
|
|
}
|
|
}
|
|
}
|
|
|
|
return d;
|
|
}
|
|
},
|
|
|
|
set_focus_on_row: function set_focus_on_row(idx) {
|
|
var me = this;
|
|
if (!idx) {
|
|
idx = me.grid_rows.length - 1;
|
|
}
|
|
setTimeout(function () {
|
|
me.grid_rows[idx].row.find('input[type="Text"],textarea,select').filter(':visible:first').focus();
|
|
}, 100);
|
|
},
|
|
|
|
setup_visible_columns: function setup_visible_columns() {
|
|
if (this.visible_columns) return;
|
|
|
|
var total_colsize = 1,
|
|
fields = this.editable_fields || this.docfields;
|
|
|
|
this.visible_columns = [];
|
|
|
|
for (var ci in fields) {
|
|
var _df = fields[ci];
|
|
|
|
df = this.fields_map[_df.fieldname];
|
|
|
|
if (!df.hidden && (this.editable_fields || df.in_list_view) && (this.frm && this.frm.get_perm(df.permlevel, "read") || !this.frm) && !in_list(frappe.model.layout_fields, df.fieldtype)) {
|
|
|
|
if (df.columns) {
|
|
df.colsize = df.columns;
|
|
} else {
|
|
var colsize = 2;
|
|
switch (df.fieldtype) {
|
|
case "Text":
|
|
case "Small Text":
|
|
colsize = 3;
|
|
break;
|
|
case "Check":
|
|
colsize = 1;
|
|
}
|
|
df.colsize = colsize;
|
|
}
|
|
|
|
if (df.columns) {
|
|
df.colsize = df.columns;
|
|
} else {
|
|
var colsize = 2;
|
|
switch (df.fieldtype) {
|
|
case "Text":
|
|
case "Small Text":
|
|
colsize = 3;break;
|
|
case "Check":
|
|
colsize = 1;
|
|
}
|
|
df.colsize = colsize;
|
|
}
|
|
|
|
total_colsize += df.colsize;
|
|
if (total_colsize > 11) return false;
|
|
this.visible_columns.push([df, df.colsize]);
|
|
}
|
|
}
|
|
|
|
var passes = 0;
|
|
while (total_colsize < 11 && passes < 12) {
|
|
for (var i in this.visible_columns) {
|
|
var df = this.visible_columns[i][0];
|
|
var colsize = this.visible_columns[i][1];
|
|
if (colsize > 1 && colsize < 11 && !in_list(frappe.model.std_fields_list, df.fieldname)) {
|
|
|
|
if (passes < 3 && ["Int", "Currency", "Float", "Check", "Percent"].indexOf(df.fieldtype) !== -1) {
|
|
continue;
|
|
}
|
|
|
|
this.visible_columns[i][1] += 1;
|
|
total_colsize++;
|
|
}
|
|
|
|
if (total_colsize > 10) break;
|
|
}
|
|
passes++;
|
|
}
|
|
},
|
|
|
|
is_editable: function is_editable() {
|
|
return this.display_status == "Write" && !this.static_rows;
|
|
},
|
|
is_sortable: function is_sortable() {
|
|
return this.sortable_status || this.is_editable();
|
|
},
|
|
only_sortable: function only_sortable(status) {
|
|
if (status === undefined ? true : status) {
|
|
this.sortable_status = true;
|
|
this.static_rows = true;
|
|
}
|
|
},
|
|
set_multiple_add: function set_multiple_add(link, qty) {
|
|
if (this.multiple_set) return;
|
|
var me = this;
|
|
var link_field = frappe.meta.get_docfield(this.df.options, link);
|
|
var btn = $(this.wrapper).find(".grid-add-multiple-rows");
|
|
|
|
btn.removeClass('hide');
|
|
|
|
btn.on("click", function () {
|
|
new frappe.ui.form.LinkSelector({
|
|
doctype: link_field.options,
|
|
fieldname: link,
|
|
qty_fieldname: qty,
|
|
target: me,
|
|
txt: ""
|
|
});
|
|
return false;
|
|
});
|
|
this.multiple_set = true;
|
|
},
|
|
setup_allow_bulk_edit: function setup_allow_bulk_edit() {
|
|
var me = this;
|
|
if (this.frm && this.frm.get_docfield(this.df.fieldname).allow_bulk_edit) {
|
|
me.setup_download();
|
|
|
|
$(this.wrapper).find(".grid-upload").removeClass("hide").on("click", function () {
|
|
frappe.prompt({ fieldtype: "Attach", label: "Upload File" }, function (data) {
|
|
var data = frappe.utils.csv_to_array(frappe.upload.get_string(data.upload_file));
|
|
|
|
var fieldnames = data[2];
|
|
|
|
me.frm.clear_table(me.df.fieldname);
|
|
$.each(data, function (i, row) {
|
|
if (i > 4) {
|
|
var blank_row = true;
|
|
$.each(row, function (ci, value) {
|
|
if (value) {
|
|
blank_row = false;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (!blank_row) {
|
|
var d = me.frm.add_child(me.df.fieldname);
|
|
$.each(row, function (ci, value) {
|
|
var fieldname = fieldnames[ci];
|
|
var df = frappe.meta.get_docfield(me.df.options, fieldname);
|
|
|
|
if (df.fieldtype === "Date" && value) {
|
|
value = frappe.datetime.user_to_str(value);
|
|
}
|
|
|
|
if (df.fieldtype === "Int" || df.fieldtype === "Check") {
|
|
value = cint(value);
|
|
}
|
|
|
|
d[fieldnames[ci]] = value;
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
me.frm.refresh_field(me.df.fieldname);
|
|
frappe.msgprint({ message: __('Table updated'), title: __('Success'), indicator: 'green' });
|
|
}, __("Edit via Upload"), __("Update"));
|
|
return false;
|
|
});
|
|
}
|
|
},
|
|
setup_download: function setup_download() {
|
|
var me = this;
|
|
$(this.wrapper).find(".grid-download").removeClass("hide").on("click", function () {
|
|
var data = [];
|
|
var docfields = [];
|
|
data.push([__("Bulk Edit {0}", [me.df.label])]);
|
|
data.push([]);
|
|
data.push([]);
|
|
data.push([]);
|
|
data.push(["------"]);
|
|
$.each(frappe.get_meta(me.df.options).fields, function (i, df) {
|
|
if (frappe.model.is_value_type(df.fieldtype)) {
|
|
data[1].push(df.label);
|
|
data[2].push(df.fieldname);
|
|
data[3].push(df.description || "");
|
|
docfields.push(df);
|
|
}
|
|
});
|
|
|
|
$.each(me.frm.doc[me.df.fieldname] || [], function (i, d) {
|
|
var row = [];
|
|
$.each(data[2], function (i, fieldname) {
|
|
var value = d[fieldname];
|
|
|
|
if (docfields[i].fieldtype === "Date" && value) {
|
|
value = frappe.datetime.str_to_user(value);
|
|
}
|
|
|
|
row.push(value || "");
|
|
});
|
|
data.push(row);
|
|
});
|
|
|
|
frappe.tools.downloadify(data, null, me.df.label);
|
|
return false;
|
|
});
|
|
},
|
|
add_custom_button: function add_custom_button(label, click) {
|
|
var btn = this.custom_buttons[label];
|
|
if (!btn) {
|
|
btn = $('<button class="btn btn-default btn-xs btn-custom">' + label + '</button>').css('margin-right', '10px').prependTo(this.grid_buttons).on('click', click);
|
|
this.custom_buttons[label] = btn;
|
|
} else {
|
|
btn.removeClass('hidden');
|
|
}
|
|
},
|
|
clear_custom_buttons: function clear_custom_buttons() {
|
|
this.grid_buttons.find('.btn-custom').addClass('hidden');
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.GridRow = Class.extend({
|
|
init: function init(opts) {
|
|
this.on_grid_fields_dict = {};
|
|
this.on_grid_fields = [];
|
|
this.row_check_html = '<input type="checkbox" class="grid-row-check pull-left">';
|
|
this.columns = {};
|
|
this.columns_list = [];
|
|
$.extend(this, opts);
|
|
this.make();
|
|
},
|
|
make: function make() {
|
|
var me = this;
|
|
|
|
this.wrapper = $('<div class="grid-row"></div>').appendTo(this.parent).data("grid_row", this);
|
|
this.row = $('<div class="data-row row"></div>').appendTo(this.wrapper).on("click", function (e) {
|
|
if ($(e.target).hasClass('grid-row-check') || $(e.target).hasClass('row-index') || $(e.target).parent().hasClass('row-index')) {
|
|
return;
|
|
}
|
|
if (me.grid.allow_on_grid_editing() && me.grid.is_editable()) {} else {
|
|
me.toggle_view();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (this.grid.template && !this.grid.meta.editable_grid) {
|
|
this.render_template();
|
|
} else {
|
|
this.render_row();
|
|
}
|
|
if (this.doc) {
|
|
this.set_data();
|
|
}
|
|
},
|
|
set_data: function set_data() {
|
|
this.wrapper.data({
|
|
"doc": this.doc
|
|
});
|
|
},
|
|
set_row_index: function set_row_index() {
|
|
if (this.doc) {
|
|
this.wrapper.attr('data-name', this.doc.name).attr("data-idx", this.doc.idx).find(".row-index span, .grid-form-row-index").html(this.doc.idx);
|
|
}
|
|
},
|
|
select: function select(checked) {
|
|
this.doc.__checked = checked ? 1 : 0;
|
|
},
|
|
refresh_check: function refresh_check() {
|
|
this.wrapper.find('.grid-row-check').prop('checked', this.doc ? !!this.doc.__checked : false);
|
|
this.grid.refresh_remove_rows_button();
|
|
},
|
|
remove: function remove() {
|
|
var me = this;
|
|
if (this.grid.is_editable()) {
|
|
if (this.frm) {
|
|
if (this.get_open_form()) {
|
|
this.hide_form();
|
|
}
|
|
|
|
this.frm.script_manager.trigger("before_" + this.grid.df.fieldname + "_remove", this.doc.doctype, this.doc.name);
|
|
|
|
frappe.model.clear_doc(this.doc.doctype, this.doc.name);
|
|
|
|
this.frm.script_manager.trigger(this.grid.df.fieldname + "_remove", this.doc.doctype, this.doc.name);
|
|
this.frm.dirty();
|
|
} else {
|
|
this.grid.df.data = this.grid.df.data.filter(function (d) {
|
|
return d.name !== me.doc.name;
|
|
});
|
|
|
|
this.grid.df.data.forEach(function (d, i) {
|
|
d.idx = i + 1;
|
|
});
|
|
}
|
|
this.grid.refresh();
|
|
}
|
|
},
|
|
insert: function insert(show, below) {
|
|
var idx = this.doc.idx;
|
|
if (below) idx++;
|
|
this.toggle_view(false);
|
|
this.grid.add_new_row(idx, null, show);
|
|
},
|
|
refresh: function refresh() {
|
|
if (this.frm && this.doc) {
|
|
this.doc = locals[this.doc.doctype][this.doc.name];
|
|
}
|
|
|
|
this.visible_columns = null;
|
|
|
|
if (this.grid.template && !this.grid.meta.editable_grid) {
|
|
this.render_template();
|
|
} else {
|
|
this.render_row(true);
|
|
}
|
|
|
|
if (this.grid_form) {
|
|
this.grid_form.layout && this.grid_form.layout.refresh(this.doc);
|
|
}
|
|
},
|
|
render_template: function render_template() {
|
|
this.set_row_index();
|
|
|
|
if (this.row_display) {
|
|
this.row_display.remove();
|
|
}
|
|
var index_html = '';
|
|
|
|
if (this.doc) {
|
|
if (!this.row_index) {
|
|
this.row_index = $('<div style="float: left; margin-left: 15px; margin-top: 8px; \
|
|
margin-right: -20px;">' + this.row_check_html + ' <span></span></div>').appendTo(this.row);
|
|
}
|
|
this.row_index.find('span').html(this.doc.idx);
|
|
}
|
|
|
|
this.row_display = $('<div class="row-data sortable-handle template-row">' + +'</div>').appendTo(this.row).html(frappe.render(this.grid.template, {
|
|
doc: this.doc ? frappe.get_format_helper(this.doc) : null,
|
|
frm: this.frm,
|
|
row: this
|
|
}));
|
|
},
|
|
render_row: function render_row(refresh) {
|
|
var me = this;
|
|
this.set_row_index();
|
|
|
|
if (!this.row_index) {
|
|
var txt = this.doc ? this.doc.idx : " ";
|
|
this.row_index = $('<div class="row-index sortable-handle col col-xs-1">\n\t\t\t\t\t' + this.row_check_html + '\n\t\t\t\t<span>' + txt + '</span></div>').appendTo(this.row).on('click', function (e) {
|
|
if (!$(e.target).hasClass('grid-row-check')) {
|
|
me.toggle_view();
|
|
}
|
|
});
|
|
} else {
|
|
this.row_index.find('span').html(txt);
|
|
}
|
|
|
|
this.setup_columns();
|
|
this.add_open_form_button();
|
|
this.refresh_check();
|
|
|
|
if (this.frm && this.doc) {
|
|
$(this.frm.wrapper).trigger("grid-row-render", [this]);
|
|
}
|
|
},
|
|
|
|
make_editable: function make_editable() {
|
|
this.row.toggleClass('editable-row', this.grid.is_editable());
|
|
},
|
|
|
|
is_too_small: function is_too_small() {
|
|
return this.row.width() ? this.row.width() < 300 : false;
|
|
},
|
|
|
|
add_open_form_button: function add_open_form_button() {
|
|
var me = this;
|
|
if (this.doc && !this.grid.df.in_place_edit) {
|
|
if (!this.open_form_button) {
|
|
this.open_form_button = $('<a class="close btn-open-row">\
|
|
<span class="octicon octicon-triangle-down"></span></a>').appendTo($('<div class="col col-xs-1 sortable-handle"></div>').appendTo(this.row)).on('click', function () {
|
|
me.toggle_view();return false;
|
|
});
|
|
|
|
if (this.is_too_small()) {
|
|
this.open_form_button.css({ 'margin-right': '-2px' });
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
setup_columns: function setup_columns() {
|
|
var me = this;
|
|
this.focus_set = false;
|
|
this.grid.setup_visible_columns();
|
|
|
|
for (var ci in this.grid.visible_columns) {
|
|
var df = this.grid.visible_columns[ci][0],
|
|
colsize = this.grid.visible_columns[ci][1],
|
|
txt = this.doc ? frappe.format(this.doc[df.fieldname], df, null, this.doc) : __(df.label);
|
|
|
|
if (this.doc && df.fieldtype === "Select") {
|
|
txt = __(txt);
|
|
}
|
|
|
|
if (!this.columns[df.fieldname]) {
|
|
var column = this.make_column(df, colsize, txt, ci);
|
|
} else {
|
|
var column = this.columns[df.fieldname];
|
|
this.refresh_field(df.fieldname, txt);
|
|
}
|
|
|
|
if (this.doc) {
|
|
if (df.reqd && !txt) {
|
|
column.addClass('error');
|
|
}
|
|
if (df.reqd || df.bold) {
|
|
column.addClass('bold');
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
make_column: function make_column(df, colsize, txt, ci) {
|
|
var me = this;
|
|
var add_class = ["Text", "Small Text"].indexOf(df.fieldtype) !== -1 ? " grid-overflow-no-ellipsis" : "";
|
|
add_class += ["Int", "Currency", "Float", "Percent"].indexOf(df.fieldtype) !== -1 ? " text-right" : "";
|
|
add_class += ["Check"].indexOf(df.fieldtype) !== -1 ? " text-center" : "";
|
|
|
|
var $col = $('<div class="col grid-static-col col-xs-' + colsize + ' ' + add_class + '"></div>').attr("data-fieldname", df.fieldname).attr("data-fieldtype", df.fieldtype).data("df", df).appendTo(this.row).on('click', function () {
|
|
if (frappe.ui.form.editable_row === me) {
|
|
return;
|
|
}
|
|
var out = me.toggle_editable_row();
|
|
var col = this;
|
|
setTimeout(function () {
|
|
$(col).find('input[type="Text"]:first').focus();
|
|
}, 500);
|
|
return out;
|
|
});
|
|
|
|
$col.field_area = $('<div class="field-area"></div>').appendTo($col).toggle(false);
|
|
$col.static_area = $('<div class="static-area ellipsis"></div>').appendTo($col).html(txt);
|
|
$col.df = df;
|
|
$col.column_index = ci;
|
|
|
|
this.columns[df.fieldname] = $col;
|
|
this.columns_list.push($col);
|
|
|
|
return $col;
|
|
},
|
|
|
|
activate: function activate() {
|
|
this.toggle_editable_row(true);
|
|
return this;
|
|
},
|
|
|
|
toggle_editable_row: function toggle_editable_row(show) {
|
|
var me = this;
|
|
|
|
if (this.grid.allow_on_grid_editing() && this.grid.is_editable() && this.doc && show !== false) {
|
|
if (frappe.ui.form.editable_row && frappe.ui.form.editable_row !== this) {
|
|
frappe.ui.form.editable_row.toggle_editable_row(false);
|
|
}
|
|
|
|
this.row.toggleClass('editable-row', true);
|
|
|
|
this.columns_list.forEach(function (column) {
|
|
me.make_control(column);
|
|
column.static_area.toggle(false);
|
|
column.field_area.toggle(true);
|
|
});
|
|
|
|
frappe.ui.form.editable_row = this;
|
|
return false;
|
|
} else {
|
|
this.row.toggleClass('editable-row', false);
|
|
this.columns_list.forEach(function (column) {
|
|
column.static_area.toggle(true);
|
|
column.field_area && column.field_area.toggle(false);
|
|
});
|
|
frappe.ui.form.editable_row = null;
|
|
}
|
|
},
|
|
|
|
make_control: function make_control(column) {
|
|
if (column.field) return;
|
|
|
|
var me = this,
|
|
parent = column.field_area,
|
|
df = column.df;
|
|
|
|
if (df.fieldtype == 'Text Editor') {
|
|
df.fieldtype = 'Text';
|
|
}
|
|
|
|
var field = frappe.ui.form.make_control({
|
|
df: df,
|
|
parent: parent,
|
|
only_input: true,
|
|
with_link_btn: true,
|
|
doc: this.doc,
|
|
doctype: this.doc.doctype,
|
|
docname: this.doc.name,
|
|
frm: this.grid.frm,
|
|
grid: this.grid,
|
|
grid_row: this,
|
|
value: this.doc[df.fieldname]
|
|
});
|
|
|
|
field.get_query = this.grid.get_field(df.fieldname).get_query;
|
|
field.refresh();
|
|
if (field.$input) {
|
|
field.$input.addClass('input-sm').attr('data-col-idx', column.column_index).attr('placeholder', __(df.label));
|
|
|
|
if (this.columns_list && this.columns_list.slice(-1)[0] === column) {
|
|
field.$input.attr('data-last-input', 1);
|
|
}
|
|
}
|
|
|
|
this.set_arrow_keys(field);
|
|
column.field = field;
|
|
this.on_grid_fields_dict[df.fieldname] = field;
|
|
this.on_grid_fields.push(field);
|
|
},
|
|
|
|
set_arrow_keys: function set_arrow_keys(field) {
|
|
var me = this;
|
|
if (field.$input) {
|
|
field.$input.on('keydown', function (e) {
|
|
var _frappe$ui$keyCode = frappe.ui.keyCode,
|
|
TAB = _frappe$ui$keyCode.TAB,
|
|
UP_ARROW = _frappe$ui$keyCode.UP_ARROW,
|
|
DOWN_ARROW = _frappe$ui$keyCode.DOWN_ARROW;
|
|
|
|
if (!in_list([TAB, UP_ARROW, DOWN_ARROW], e.which)) {
|
|
return;
|
|
}
|
|
|
|
var values = me.grid.get_data();
|
|
var fieldname = $(this).attr('data-fieldname');
|
|
var fieldtype = $(this).attr('data-fieldtype');
|
|
|
|
var move_up_down = function move_up_down(base) {
|
|
if (in_list(['Text', 'Small Text'], fieldtype)) {
|
|
return;
|
|
}
|
|
|
|
base.toggle_editable_row();
|
|
setTimeout(function () {
|
|
var input = base.columns[fieldname].field.$input;
|
|
if (input) {
|
|
input.focus();
|
|
}
|
|
}, 400);
|
|
};
|
|
|
|
if (e.which == TAB && !e.shiftKey) {
|
|
if ($(this).attr('data-last-input') || me.grid.wrapper.find('.grid-row :input:enabled:last').get(0) === this) {
|
|
setTimeout(function () {
|
|
if (me.doc.idx === values.length) {
|
|
me.grid.add_new_row(null, null, true);
|
|
me.grid.grid_rows[me.grid.grid_rows.length - 1].toggle_editable_row();
|
|
me.grid.set_focus_on_row();
|
|
} else {
|
|
me.grid.grid_rows[me.doc.idx].toggle_editable_row();
|
|
me.grid.set_focus_on_row(me.doc.idx + 1);
|
|
}
|
|
}, 500);
|
|
}
|
|
} else if (e.which == UP_ARROW) {
|
|
if (me.doc.idx > 1) {
|
|
var prev = me.grid.grid_rows[me.doc.idx - 2];
|
|
move_up_down(prev);
|
|
}
|
|
} else if (e.which == DOWN_ARROW) {
|
|
if (me.doc.idx < values.length) {
|
|
var next = me.grid.grid_rows[me.doc.idx];
|
|
move_up_down(next);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
get_open_form: function get_open_form() {
|
|
return frappe.ui.form.get_open_grid_form();
|
|
},
|
|
|
|
toggle_view: function toggle_view(show, callback) {
|
|
if (!this.doc) {
|
|
return this;
|
|
}
|
|
|
|
if (this.frm) {
|
|
this.doc = locals[this.doc.doctype][this.doc.name];
|
|
}
|
|
|
|
var open_row = this.get_open_form();
|
|
|
|
if (show === undefined) show = !!!open_row;
|
|
|
|
document.activeElement && document.activeElement.blur();
|
|
|
|
if (show && open_row) {
|
|
if (open_row == this) {
|
|
callback && callback();
|
|
return;
|
|
} else {
|
|
open_row.toggle_view(false);
|
|
}
|
|
}
|
|
|
|
if (show) {
|
|
this.show_form();
|
|
} else {
|
|
this.hide_form();
|
|
}
|
|
callback && callback();
|
|
|
|
return this;
|
|
},
|
|
show_form: function show_form() {
|
|
if (!this.grid_form) {
|
|
this.grid_form = new frappe.ui.form.GridRowForm({
|
|
row: this
|
|
});
|
|
}
|
|
this.grid_form.render();
|
|
this.row.toggle(false);
|
|
|
|
frappe.dom.freeze("", "dark");
|
|
cur_frm.cur_grid = this;
|
|
this.wrapper.addClass("grid-row-open");
|
|
if (!frappe.dom.is_element_in_viewport(this.wrapper)) {
|
|
frappe.utils.scroll_to(this.wrapper, true, 15);
|
|
}
|
|
|
|
if (this.frm) {
|
|
this.frm.script_manager.trigger(this.doc.parentfield + "_on_form_rendered");
|
|
this.frm.script_manager.trigger("form_render", this.doc.doctype, this.doc.name);
|
|
}
|
|
},
|
|
hide_form: function hide_form() {
|
|
frappe.dom.unfreeze();
|
|
this.row.toggle(true);
|
|
this.refresh();
|
|
cur_frm.cur_grid = null;
|
|
this.wrapper.removeClass("grid-row-open");
|
|
},
|
|
open_prev: function open_prev() {
|
|
if (this.grid.grid_rows[this.doc.idx - 2]) {
|
|
this.grid.grid_rows[this.doc.idx - 2].toggle_view(true);
|
|
}
|
|
},
|
|
open_next: function open_next() {
|
|
if (this.grid.grid_rows[this.doc.idx]) {
|
|
this.grid.grid_rows[this.doc.idx].toggle_view(true);
|
|
} else {
|
|
this.grid.add_new_row(null, null, true);
|
|
}
|
|
},
|
|
refresh_field: function refresh_field(fieldname, txt) {
|
|
var df = this.grid.get_docfield(fieldname) || undefined;
|
|
|
|
if (!df) {
|
|
df = this.grid.visible_columns.find(function (col) {
|
|
return col[0].fieldname === fieldname;
|
|
});
|
|
if (df && this.doc) {
|
|
var txt = frappe.format(this.doc[fieldname], df[0], null, this.doc);
|
|
}
|
|
}
|
|
|
|
if (txt === undefined && this.frm) {
|
|
var txt = frappe.format(this.doc[fieldname], df, null, this.frm.doc);
|
|
}
|
|
|
|
var column = this.columns[fieldname];
|
|
if (column) {
|
|
column.static_area.html(txt || "");
|
|
if (df && df.reqd) {
|
|
column.toggleClass('error', !!(txt === null || txt === ''));
|
|
}
|
|
}
|
|
|
|
var field = this.on_grid_fields_dict[fieldname];
|
|
if (field) {
|
|
field.docname = this.doc.name;
|
|
field.refresh();
|
|
}
|
|
|
|
if (this.grid_form) {
|
|
this.grid_form.refresh_field(fieldname);
|
|
}
|
|
},
|
|
get_field: function get_field(fieldname) {
|
|
var field = this.on_grid_fields_dict[fieldname];
|
|
if (field) {
|
|
return field;
|
|
} else if (this.grid_form) {
|
|
return this.grid_form.fields_dict[fieldname];
|
|
} else {
|
|
throw 'fieldname ' + fieldname + ' not found';
|
|
}
|
|
},
|
|
|
|
get_visible_columns: function get_visible_columns(blacklist) {
|
|
var me = this;
|
|
var visible_columns = $.map(this.docfields, function (df) {
|
|
var visible = !df.hidden && df.in_list_view && me.grid.frm.get_perm(df.permlevel, "read") && !in_list(frappe.model.layout_fields, df.fieldtype) && !in_list(blacklist, df.fieldname);
|
|
|
|
return visible ? df : null;
|
|
});
|
|
return visible_columns;
|
|
},
|
|
set_field_property: function set_field_property(fieldname, property, value) {
|
|
var me = this;
|
|
|
|
var set_property = function set_property(field) {
|
|
if (!field) return;
|
|
field.df[property] = value;
|
|
field.refresh();
|
|
};
|
|
|
|
if (this.grid_form) {
|
|
set_property(this.grid_form.fields_dict[fieldname]);
|
|
this.grid_form.layout && this.grid_form.layout.refresh_sections();
|
|
}
|
|
|
|
set_property(this.on_grid_fields_dict[fieldname]);
|
|
},
|
|
toggle_reqd: function toggle_reqd(fieldname, reqd) {
|
|
this.set_field_property(fieldname, 'reqd', reqd ? 1 : 0);
|
|
},
|
|
toggle_display: function toggle_display(fieldname, show) {
|
|
this.set_field_property(fieldname, 'hidden', show ? 0 : 1);
|
|
},
|
|
toggle_editable: function toggle_editable(fieldname, editable) {
|
|
this.set_field_property(fieldname, 'read_only', editable ? 0 : 1);
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.GridRowForm = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.wrapper = $('<div class="form-in-grid"></div>').appendTo(this.row.wrapper);
|
|
},
|
|
render: function render() {
|
|
var me = this;
|
|
this.make_form();
|
|
this.form_area.empty();
|
|
|
|
this.layout = new frappe.ui.form.Layout({
|
|
fields: this.row.docfields,
|
|
body: this.form_area,
|
|
no_submit_on_enter: true,
|
|
frm: this.row.frm
|
|
});
|
|
this.layout.make();
|
|
|
|
this.fields = this.layout.fields;
|
|
this.fields_dict = this.layout.fields_dict;
|
|
|
|
this.layout.refresh(this.row.doc);
|
|
|
|
for (var fieldname in this.row.grid.fieldinfo || {}) {
|
|
var fi = this.row.grid.fieldinfo[fieldname];
|
|
$.extend(me.fields_dict[fieldname], fi);
|
|
}
|
|
|
|
this.toggle_add_delete_button_display(this.wrapper);
|
|
|
|
this.row.grid.open_grid_row = this;
|
|
|
|
this.set_focus();
|
|
},
|
|
make_form: function make_form() {
|
|
if (!this.form_area) {
|
|
$(frappe.render_template("grid_form", { grid: this })).appendTo(this.wrapper);
|
|
this.form_area = this.wrapper.find(".form-area");
|
|
this.row.set_row_index();
|
|
this.set_form_events();
|
|
}
|
|
},
|
|
set_form_events: function set_form_events() {
|
|
var me = this;
|
|
this.wrapper.find(".grid-delete-row").on('click', function () {
|
|
me.row.remove();return false;
|
|
});
|
|
this.wrapper.find(".grid-insert-row").on('click', function () {
|
|
me.row.insert(true);return false;
|
|
});
|
|
this.wrapper.find(".grid-insert-row-below").on('click', function () {
|
|
me.row.insert(true, true);return false;
|
|
});
|
|
this.wrapper.find(".grid-append-row").on('click', function () {
|
|
me.row.toggle_view(false);
|
|
me.row.grid.add_new_row(me.row.doc.idx + 1, null, true);
|
|
return false;
|
|
});
|
|
this.wrapper.find(".grid-form-heading, .grid-footer-toolbar").on("click", function () {
|
|
me.row.toggle_view();
|
|
return false;
|
|
});
|
|
},
|
|
toggle_add_delete_button_display: function toggle_add_delete_button_display($parent) {
|
|
$parent.find(".grid-header-toolbar .btn, .grid-footer-toolbar .btn").toggle(this.row.grid.is_editable());
|
|
},
|
|
refresh_field: function refresh_field(fieldname) {
|
|
if (this.fields_dict[fieldname]) {
|
|
this.fields_dict[fieldname].refresh();
|
|
this.layout && this.layout.refresh_dependency();
|
|
}
|
|
},
|
|
set_focus: function set_focus() {
|
|
var me = this;
|
|
setTimeout(function () {
|
|
if (me.row.frm && me.row.frm.doc.docstatus === 0 || !me.row.frm) {
|
|
var first = me.form_area.find("input:first");
|
|
if (first.length && !in_list(["Date", "Datetime", "Time"], first.attr("data-fieldtype"))) {
|
|
try {
|
|
first.get(0).focus();
|
|
} catch (e) {}
|
|
}
|
|
}
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.LinkedWith = function () {
|
|
function LinkedWith(opts) {
|
|
_classCallCheck(this, LinkedWith);
|
|
|
|
$.extend(this, opts);
|
|
}
|
|
|
|
_createClass(LinkedWith, [{
|
|
key: "show",
|
|
value: function show() {
|
|
if (!this.dialog) this.make_dialog();
|
|
|
|
$(this.dialog.body).html("<div class=\"text-muted text-center\" style=\"padding: 30px 0px\">\n\t\t\t\t" + __("Loading") + "...\n\t\t\t</div>");
|
|
|
|
this.dialog.show();
|
|
}
|
|
}, {
|
|
key: "make_dialog",
|
|
value: function make_dialog() {
|
|
var _this = this;
|
|
|
|
var me = this;
|
|
|
|
this.dialog = new frappe.ui.Dialog({
|
|
hide_on_page_refresh: true,
|
|
title: __("Linked With")
|
|
});
|
|
|
|
this.dialog.on_page_show = function () {
|
|
_this.get_linked_doctypes().then(function () {
|
|
return _this.load_doctypes();
|
|
}).then(function () {
|
|
return _this.links_not_permitted_or_missing();
|
|
}).then(function () {
|
|
return _this.get_linked_docs();
|
|
}).then(function () {
|
|
return _this.make_html();
|
|
});
|
|
};
|
|
}
|
|
}, {
|
|
key: "make_html",
|
|
value: function make_html() {
|
|
var _this2 = this;
|
|
|
|
var linked_docs = this.frm.__linked_docs;
|
|
|
|
var html = void 0;
|
|
|
|
if (Object.keys(linked_docs).length === 0) {
|
|
html = __("Not Linked to any record");
|
|
} else {
|
|
html = Object.keys(linked_docs).map(function (dt) {
|
|
var list_renderer = new frappe.views.ListRenderer({
|
|
doctype: dt,
|
|
list_view: _this2
|
|
});
|
|
return "<div class=\"list-item-table\" style=\"margin-bottom: 15px\">\n\t\t\t\t\t" + _this2.make_doc_head(dt) + "\n\t\t\t\t\t" + linked_docs[dt].map(function (value) {
|
|
value = list_renderer.prepare_data(value);
|
|
value._checkbox = 0;
|
|
value._hide_activity = 1;
|
|
|
|
var $item = $(list_renderer.get_item_html(value));
|
|
var $item_container = $('<div class="list-item-container">').append($item);
|
|
return $item_container[0].outerHTML;
|
|
}).join("") + "\n\t\t\t\t</div>";
|
|
});
|
|
}
|
|
|
|
$(this.dialog.body).html(html);
|
|
}
|
|
}, {
|
|
key: "load_doctypes",
|
|
value: function load_doctypes() {
|
|
var _this3 = this;
|
|
|
|
var already_loaded = Object.keys(locals.DocType);
|
|
var doctypes_to_load = [];
|
|
|
|
if (this.frm.__linked_doctypes) {
|
|
doctypes_to_load = Object.keys(this.frm.__linked_doctypes).filter(function (doctype) {
|
|
return !already_loaded.includes(doctype);
|
|
});
|
|
}
|
|
|
|
var promises = doctypes_to_load.map(function (dt) {
|
|
return frappe.model.with_doctype(dt, function () {
|
|
if (frappe.listview_settings[dt]) {
|
|
_this3.frm.__linked_doctypes[dt].add_fields = frappe.listview_settings[dt].add_fields;
|
|
}
|
|
});
|
|
});
|
|
|
|
return Promise.all(promises);
|
|
}
|
|
}, {
|
|
key: "links_not_permitted_or_missing",
|
|
value: function links_not_permitted_or_missing() {
|
|
var me = this;
|
|
var links = null;
|
|
|
|
if (this.frm.__linked_doctypes) {
|
|
links = Object.keys(this.frm.__linked_doctypes).filter(frappe.model.can_get_report);
|
|
}
|
|
|
|
var flag = void 0;
|
|
if (!links) {
|
|
$(this.dialog.body).html("" + (this.frm.__linked_doctypes ? __("Not enough permission to see links") : __("Not Linked to any record")));
|
|
flag = true;
|
|
}
|
|
flag = false;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
return flag ? reject() : resolve();
|
|
});
|
|
}
|
|
}, {
|
|
key: "get_linked_doctypes",
|
|
value: function get_linked_doctypes() {
|
|
var _this4 = this;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
if (_this4.frm.__linked_doctypes) {
|
|
resolve();
|
|
}
|
|
|
|
frappe.call({
|
|
method: "frappe.desk.form.linked_with.get_linked_doctypes",
|
|
args: {
|
|
doctype: _this4.frm.doctype
|
|
},
|
|
callback: function callback(r) {
|
|
_this4.frm.__linked_doctypes = r.message;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}, {
|
|
key: "get_linked_docs",
|
|
value: function get_linked_docs() {
|
|
var _this5 = this;
|
|
|
|
return frappe.call({
|
|
method: "frappe.desk.form.linked_with.get_linked_docs",
|
|
args: {
|
|
doctype: this.frm.doctype,
|
|
name: this.frm.docname,
|
|
linkinfo: this.frm.__linked_doctypes,
|
|
for_doctype: this.for_doctype
|
|
},
|
|
callback: function callback(r) {
|
|
_this5.frm.__linked_docs = r.message || {};
|
|
}
|
|
});
|
|
}
|
|
}, {
|
|
key: "make_doc_head",
|
|
value: function make_doc_head(heading) {
|
|
return "<div class=\"list-item list-item--head\">\n\t\t<div class=\"list-item__content\">\n\t\t\t" + heading + "\n\t\t</div></div>";
|
|
}
|
|
}, {
|
|
key: "make_doc_row",
|
|
value: function make_doc_row(doc, doctype) {
|
|
return "<div class=\"list-item-container\">\n\t\t\t<div class=\"list-item\">\n\t\t\t\t<div class=\"list-item__content bold\">\n\t\t\t\t\t<a href=\"#Form/" + doctype + "/" + doc.name + "\">" + doc.name + "</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>";
|
|
}
|
|
}]);
|
|
|
|
return LinkedWith;
|
|
}();
|
|
|
|
frappe.ui.form.States = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.state_fieldname = frappe.workflow.get_state_fieldname(this.frm.doctype);
|
|
|
|
if (!this.state_fieldname) return;
|
|
|
|
this.update_fields = frappe.workflow.get_update_fields(this.frm.doctype);
|
|
|
|
var me = this;
|
|
$(this.frm.wrapper).bind("render_complete", function () {
|
|
me.refresh();
|
|
});
|
|
},
|
|
|
|
setup_help: function setup_help() {
|
|
var me = this;
|
|
this.frm.page.add_action_item(__("Help"), function () {
|
|
frappe.workflow.setup(me.frm.doctype);
|
|
var state = me.get_state();
|
|
var d = new frappe.ui.Dialog({
|
|
title: "Workflow: " + frappe.workflow.workflows[me.frm.doctype].name
|
|
});
|
|
var next_html = $.map(frappe.workflow.get_transitions(me.frm.doctype, state), function (d) {
|
|
return d.action.bold() + __(" by Role ") + d.allowed;
|
|
}).join(", ") || __("None: End of Workflow").bold();
|
|
|
|
$(d.body).html("<p>" + __("Current status") + ": " + state.bold() + "</p>" + "<p>" + __("Document is only editable by users of role") + ": " + frappe.workflow.get_document_state(me.frm.doctype, state).allow_edit.bold() + "</p>" + "<p>" + __("Next actions") + ": " + next_html + "</p>" + (me.frm.doc.__islocal ? "<div class='alert alert-info'>" + __("Workflow will start after saving.") + "</div>" : "") + "<p class='help'>" + __("Note: Other permission rules may also apply") + "</p>").css({ padding: '15px' });
|
|
d.show();
|
|
}, true);
|
|
},
|
|
|
|
refresh: function refresh() {
|
|
if (this.frm.doc.__islocal) {
|
|
this.set_default_state();
|
|
return;
|
|
}
|
|
|
|
var state = this.get_state();
|
|
|
|
if (state) {
|
|
this.show_actions(state);
|
|
}
|
|
},
|
|
|
|
show_actions: function show_actions(state) {
|
|
var added = false,
|
|
me = this;
|
|
|
|
this.frm.page.clear_actions_menu();
|
|
|
|
if (this.frm.doc.__unsaved === 1) {
|
|
return;
|
|
}
|
|
|
|
$.each(frappe.workflow.get_transitions(this.frm.doctype, state), function (i, d) {
|
|
if (frappe.user_roles.includes(d.allowed)) {
|
|
added = true;
|
|
me.frm.page.add_action_item(__(d.action), function () {
|
|
var action = d.action;
|
|
|
|
var doc_before_action = copy_dict(me.frm.doc);
|
|
|
|
var next_state = frappe.workflow.get_next_state(me.frm.doctype, me.frm.doc[me.state_fieldname], action);
|
|
me.frm.doc[me.state_fieldname] = next_state;
|
|
var new_state = frappe.workflow.get_document_state(me.frm.doctype, next_state);
|
|
var new_docstatus = cint(new_state.doc_status);
|
|
|
|
if (new_state.update_field) {
|
|
me.frm.set_value(new_state.update_field, new_state.update_value);
|
|
}
|
|
|
|
var on_error = function on_error() {
|
|
frappe.model.add_to_locals(doc_before_action);
|
|
me.frm.refresh();
|
|
};
|
|
|
|
var success = function success() {
|
|
me.frm.timeline.insert_comment("Workflow", next_state);
|
|
};
|
|
if (new_docstatus == 1 && me.frm.doc.docstatus == 0) {
|
|
me.frm.savesubmit(null, success, on_error);
|
|
} else if (new_docstatus == 0 && me.frm.doc.docstatus == 0) {
|
|
me.frm.save("Save", success, null, on_error);
|
|
} else if (new_docstatus == 1 && me.frm.doc.docstatus == 1) {
|
|
me.frm.save("Update", success, null, on_error);
|
|
} else if (new_docstatus == 2 && me.frm.doc.docstatus == 1) {
|
|
me.frm.savecancel(null, success, on_error);
|
|
} else {
|
|
frappe.msgprint(__("Document Status transition from ") + me.frm.doc.docstatus + " " + __("to") + new_docstatus + " " + __("is not allowed."));
|
|
frappe.msgprint(__("Document Status transition from {0} to {1} is not allowed", [me.frm.doc.docstatus, new_docstatus]));
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
}
|
|
});
|
|
|
|
if (added) {
|
|
this.frm.page.btn_primary.addClass("hide");
|
|
this.frm.toolbar.current_status = "";
|
|
this.setup_help();
|
|
}
|
|
},
|
|
|
|
set_default_state: function set_default_state() {
|
|
var default_state = frappe.workflow.get_default_state(this.frm.doctype, this.frm.doc.docstatus);
|
|
if (default_state) {
|
|
this.frm.set_value(this.state_fieldname, default_state);
|
|
}
|
|
},
|
|
|
|
get_state: function get_state() {
|
|
if (!this.frm.doc[this.state_fieldname]) {
|
|
this.set_default_state();
|
|
}
|
|
return this.frm.doc[this.state_fieldname];
|
|
},
|
|
|
|
bind_action: function bind_action() {
|
|
var me = this;
|
|
this.dropdown.on("click", "[data-action]", function () {});
|
|
}
|
|
});
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.PrintPreview = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.make();
|
|
this.bind_events();
|
|
},
|
|
make: function make() {
|
|
this.wrapper = this.frm.page.add_view("print", frappe.render_template("print_layout", {}));
|
|
|
|
this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager"));
|
|
},
|
|
bind_events: function bind_events() {
|
|
var me = this;
|
|
this.wrapper.find(".btn-print-close").click(function () {
|
|
me.frm.hide_print();
|
|
});
|
|
|
|
$(document).on("keydown", function (e) {
|
|
if (e.which === 27 && me.frm && e.target === document.body) {
|
|
me.frm.hide_print();
|
|
}
|
|
});
|
|
|
|
this.print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
|
|
this.print_letterhead = this.wrapper.find(".print-letterhead").on("change", function () {
|
|
me.print_sel.trigger("change");
|
|
}).prop("checked", cint((frappe.model.get_doc(":Print Settings", "Print Settings") || { with_letterhead: 1 }).with_letterhead) ? true : false);
|
|
this.print_sel = this.wrapper.find(".print-preview-select").on("change", function () {
|
|
me.multilingual_preview();
|
|
});
|
|
|
|
this.language_sel = this.wrapper.find(".languages").on("change", function () {
|
|
me.lang_code = me.language_sel.val();
|
|
me.multilingual_preview();
|
|
});
|
|
|
|
this.wrapper.find(".btn-print-print").click(function () {
|
|
if (me.is_old_style()) {
|
|
me.print_old_style();
|
|
} else {
|
|
me.printit();
|
|
}
|
|
});
|
|
|
|
this.wrapper.find(".btn-print-preview").click(function () {
|
|
if (me.is_old_style()) {
|
|
me.new_page_preview_old_style();
|
|
} else {
|
|
me.new_page_preview();
|
|
}
|
|
});
|
|
|
|
this.wrapper.find(".btn-download-pdf").click(function () {
|
|
if (!me.is_old_style()) {
|
|
var w = window.open(frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?" + "doctype=" + encodeURIComponent(me.frm.doc.doctype) + "&name=" + encodeURIComponent(me.frm.doc.name) + "&format=" + me.selected_format() + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? "&_lang=" + me.lang_code : "")));
|
|
if (!w) {
|
|
frappe.msgprint(__("Please enable pop-ups"));return;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.wrapper.find(".btn-print-edit").on("click", function () {
|
|
var print_format = me.get_print_format();
|
|
if (print_format && print_format.name) {
|
|
if (print_format.print_format_builder) {
|
|
frappe.set_route("print-format-builder", print_format.name);
|
|
} else {
|
|
frappe.set_route("Form", "Print Format", print_format.name);
|
|
}
|
|
} else {
|
|
frappe.prompt({
|
|
fieldname: "print_format_name", fieldtype: "Data", reqd: 1,
|
|
label: "New Print Format Name"
|
|
}, function (data) {
|
|
frappe.route_options = {
|
|
make_new: true,
|
|
doctype: me.frm.doctype,
|
|
name: data.print_format_name
|
|
};
|
|
frappe.set_route("print-format-builder");
|
|
}, __("New Custom Print Format"), __("Start"));
|
|
}
|
|
});
|
|
},
|
|
set_user_lang: function set_user_lang() {
|
|
this.lang_code = this.frm.doc.language;
|
|
|
|
this.language_sel.empty().add_options(frappe.get_languages()).val(this.lang_code);
|
|
this.preview();
|
|
},
|
|
multilingual_preview: function multilingual_preview() {
|
|
var me = this;
|
|
if (this.is_old_style()) {
|
|
me.wrapper.find(".btn-download-pdf").toggle(false);
|
|
me.set_style();
|
|
me.preview_old_style();
|
|
} else {
|
|
me.wrapper.find(".btn-download-pdf").toggle(true);
|
|
me.preview();
|
|
}
|
|
},
|
|
preview: function preview() {
|
|
var me = this;
|
|
this.get_print_html(function (out) {
|
|
me.wrapper.find(".print-format").html(out.html);
|
|
me.show_footer();
|
|
me.set_style(out.style);
|
|
});
|
|
},
|
|
show_footer: function show_footer() {
|
|
this.wrapper.find('.print-format').css('position', 'relative');
|
|
this.wrapper.find('#footer-html').attr('style', "\n\t\t\tdisplay: block !important;\n\t\t\tposition: absolute;\n\t\t\tbottom: 0.75in;\n\t\t");
|
|
},
|
|
printit: function printit() {
|
|
this.new_page_preview(true);
|
|
},
|
|
new_page_preview: function new_page_preview(printit) {
|
|
var me = this;
|
|
var w = window.open(frappe.urllib.get_full_url("/printview?" + "doctype=" + encodeURIComponent(me.frm.doc.doctype) + "&name=" + encodeURIComponent(me.frm.doc.name) + (printit ? "&trigger_print=1" : "") + "&format=" + me.selected_format() + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? "&_lang=" + me.lang_code : "")));
|
|
if (!w) {
|
|
frappe.msgprint(__("Please enable pop-ups"));return;
|
|
}
|
|
},
|
|
get_print_html: function get_print_html(_callback) {
|
|
frappe.call({
|
|
method: "frappe.www.printview.get_html_and_style",
|
|
args: {
|
|
doc: this.frm.doc,
|
|
print_format: this.selected_format(),
|
|
no_letterhead: !this.with_letterhead() ? 1 : 0,
|
|
_lang: this.lang_code
|
|
},
|
|
callback: function callback(r) {
|
|
if (!r.exc) {
|
|
_callback(r.message);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
preview_old_style: function preview_old_style() {
|
|
var me = this;
|
|
this.with_old_style({
|
|
format: me.print_sel.val(),
|
|
callback: function callback(html) {
|
|
me.wrapper.find(".print-format").html('<div class="alert alert-warning">' + __("Warning: This Print Format is in old style and cannot be generated via the API.") + '</div>' + html);
|
|
},
|
|
no_letterhead: !this.with_letterhead(),
|
|
only_body: true,
|
|
no_heading: true
|
|
});
|
|
},
|
|
refresh_print_options: function refresh_print_options() {
|
|
this.print_formats = frappe.meta.get_print_formats(this.frm.doctype);
|
|
return this.print_sel.empty().add_options(this.print_formats);
|
|
},
|
|
with_old_style: function with_old_style(opts) {
|
|
frappe.require("/assets/js/print_format_v3.min.js", function () {
|
|
_p.build(opts.format, opts.callback, opts.no_letterhead, opts.only_body, opts.no_heading);
|
|
});
|
|
},
|
|
print_old_style: function print_old_style() {
|
|
var me = this;
|
|
frappe.require("/assets/js/print_format_v3.min.js", function () {
|
|
_p.build(me.print_sel.val(), _p.go, !me.with_letterhead());
|
|
});
|
|
},
|
|
new_page_preview_old_style: function new_page_preview_old_style() {
|
|
var me = this;
|
|
frappe.require("/assets/js/print_format_v3.min.js", function () {
|
|
_p.build(me.print_sel.val(), _p.preview, !me.with_letterhead());
|
|
});
|
|
},
|
|
selected_format: function selected_format() {
|
|
return this.print_sel.val() || this.frm.meta.default_print_format || "Standard";
|
|
},
|
|
is_old_style: function is_old_style(format) {
|
|
return this.get_print_format(format).print_format_type === "Client";
|
|
},
|
|
get_print_format: function get_print_format(format) {
|
|
if (!format) {
|
|
format = this.selected_format();
|
|
}
|
|
|
|
if (locals["Print Format"] && locals["Print Format"][format]) {
|
|
return locals["Print Format"][format];
|
|
} else {
|
|
return {};
|
|
}
|
|
},
|
|
with_letterhead: function with_letterhead() {
|
|
return this.print_letterhead.is(":checked") ? 1 : 0;
|
|
},
|
|
set_style: function set_style(style) {
|
|
frappe.dom.set_style(style || frappe.boot.print_css, "print-style");
|
|
}
|
|
});
|
|
|
|
frappe.ui.get_print_settings = function (pdf, callback, letter_head) {
|
|
var print_settings = locals[":Print Settings"]["Print Settings"];
|
|
|
|
var default_letter_head = locals[":Company"] && frappe.defaults.get_default('company') ? locals[":Company"][frappe.defaults.get_default('company')]["default_letter_head"] : '';
|
|
|
|
var columns = [{
|
|
fieldtype: "Check",
|
|
fieldname: "with_letter_head",
|
|
label: __("With Letter head")
|
|
}, {
|
|
fieldtype: "Select",
|
|
fieldname: "letter_head",
|
|
label: __("Letter Head"),
|
|
depends_on: "with_letter_head",
|
|
options: $.map(frappe.boot.letter_heads, function (i, d) {
|
|
return d;
|
|
}),
|
|
default: letter_head || default_letter_head
|
|
}];
|
|
|
|
if (pdf) {
|
|
columns.push({
|
|
fieldtype: "Select",
|
|
fieldname: "orientation",
|
|
label: __("Orientation"),
|
|
options: "Landscape\nPortrait",
|
|
default: "Landscape"
|
|
});
|
|
}
|
|
|
|
frappe.prompt(columns, function (data) {
|
|
var data = $.extend(print_settings, data);
|
|
if (!data.with_letter_head) {
|
|
data.letter_head = null;
|
|
}
|
|
if (data.letter_head) {
|
|
data.letter_head = frappe.boot.letter_heads[print_settings.letter_head];
|
|
}
|
|
callback(data);
|
|
}, __("Print Settings"));
|
|
};
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
frappe.ui.form.Sidebar = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
},
|
|
|
|
make: function make() {
|
|
var sidebar_content = frappe.render_template("form_sidebar", { doctype: this.frm.doctype, frm: this.frm });
|
|
|
|
this.sidebar = $('<div class="form-sidebar overlay-sidebar hidden-xs hidden-sm"></div>').html(sidebar_content).appendTo(this.page.sidebar.empty());
|
|
|
|
this.ratings = this.sidebar.find(".sidebar-rating");
|
|
this.comments = this.sidebar.find(".sidebar-comments");
|
|
this.user_actions = this.sidebar.find(".user-actions");
|
|
this.image_section = this.sidebar.find(".sidebar-image-section");
|
|
this.image_wrapper = this.image_section.find('.sidebar-image-wrapper');
|
|
|
|
this.make_assignments();
|
|
this.make_attachments();
|
|
this.make_shared();
|
|
this.make_viewers();
|
|
this.make_tags();
|
|
this.make_like();
|
|
|
|
this.bind_events();
|
|
frappe.ui.form.setup_user_image_event(this.frm);
|
|
|
|
this.refresh();
|
|
},
|
|
|
|
bind_events: function bind_events() {
|
|
var me = this;
|
|
|
|
this.comments.on("click", function () {
|
|
frappe.utils.scroll_to(me.frm.footer.wrapper.find(".form-comments"), true);
|
|
});
|
|
|
|
this.like_icon.on("click", function () {
|
|
frappe.ui.toggle_like(me.like_icon, me.frm.doctype, me.frm.doc.name, function () {
|
|
me.refresh_like();
|
|
});
|
|
});
|
|
},
|
|
|
|
refresh: function refresh() {
|
|
if (this.frm.doc.__islocal) {
|
|
this.sidebar.toggle(false);
|
|
} else {
|
|
this.sidebar.toggle(true);
|
|
this.frm.assign_to.refresh();
|
|
this.frm.attachments.refresh();
|
|
this.frm.shared.refresh();
|
|
this.frm.viewers.refresh();
|
|
this.frm.tags && this.frm.tags.refresh(this.frm.doc._user_tags);
|
|
this.sidebar.find(".modified-by").html(__("{0} edited this {1}", ["<strong>" + frappe.user.full_name(this.frm.doc.modified_by) + "</strong>", "<br>" + comment_when(this.frm.doc.modified)]));
|
|
this.sidebar.find(".created-by").html(__("{0} created this {1}", ["<strong>" + frappe.user.full_name(this.frm.doc.owner) + "</strong>", "<br>" + comment_when(this.frm.doc.creation)]));
|
|
|
|
this.refresh_like();
|
|
this.setup_ratings();
|
|
frappe.ui.form.set_user_image(this.frm);
|
|
}
|
|
},
|
|
|
|
refresh_comments: function refresh_comments() {
|
|
var comments = $.map(this.frm.timeline.get_communications(), function (c) {
|
|
return c.communication_type === "Communication" || c.communication_type == "Comment" && c.comment_type === "Comment" ? c : null;
|
|
});
|
|
this.comments.find(".n-comments").html(comments.length);
|
|
},
|
|
|
|
make_tags: function make_tags() {
|
|
var me = this;
|
|
if (this.frm.meta.issingle) {
|
|
this.sidebar.find(".form-tags").toggle(false);
|
|
return;
|
|
}
|
|
|
|
this.frm.tags = new frappe.ui.TagEditor({
|
|
parent: this.sidebar.find(".tag-area"),
|
|
frm: this.frm,
|
|
on_change: function on_change(user_tags) {
|
|
me.frm.doc._user_tags = user_tags;
|
|
}
|
|
});
|
|
},
|
|
make_attachments: function make_attachments() {
|
|
var me = this;
|
|
this.frm.attachments = new frappe.ui.form.Attachments({
|
|
parent: me.sidebar.find(".form-attachments"),
|
|
frm: me.frm
|
|
});
|
|
},
|
|
make_assignments: function make_assignments() {
|
|
this.frm.assign_to = new frappe.ui.form.AssignTo({
|
|
parent: this.sidebar.find(".form-assignments"),
|
|
frm: this.frm
|
|
});
|
|
},
|
|
make_shared: function make_shared() {
|
|
this.frm.shared = new frappe.ui.form.Share({
|
|
frm: this.frm,
|
|
parent: this.sidebar.find(".form-shared")
|
|
});
|
|
},
|
|
make_viewers: function make_viewers() {
|
|
this.frm.viewers = new frappe.ui.form.Viewers({
|
|
frm: this.frm,
|
|
parent: this.sidebar.find(".form-viewers")
|
|
});
|
|
},
|
|
add_user_action: function add_user_action(label, click) {
|
|
return $('<a>').html(label).appendTo($('<li class="user-action-row">').appendTo(this.user_actions.removeClass("hidden"))).on("click", click);
|
|
},
|
|
clear_user_actions: function clear_user_actions() {
|
|
this.user_actions.addClass("hidden");
|
|
this.user_actions.find(".user-action-row").remove();
|
|
},
|
|
|
|
make_like: function make_like() {
|
|
this.like_wrapper = this.sidebar.find(".liked-by");
|
|
this.like_icon = this.sidebar.find(".liked-by .octicon-heart");
|
|
this.like_count = this.sidebar.find(".liked-by .likes-count");
|
|
frappe.ui.setup_like_popover(this.sidebar.find(".liked-by-parent"), ".liked-by");
|
|
},
|
|
|
|
refresh_like: function refresh_like() {
|
|
if (!this.like_icon) {
|
|
return;
|
|
}
|
|
|
|
this.like_wrapper.attr("data-liked-by", this.frm.doc._liked_by);
|
|
|
|
this.like_icon.toggleClass("text-extra-muted not-liked", !frappe.ui.is_liked(this.frm.doc)).attr("data-doctype", this.frm.doctype).attr("data-name", this.frm.doc.name);
|
|
|
|
this.like_count.text(JSON.parse(this.frm.doc._liked_by || "[]").length);
|
|
},
|
|
|
|
refresh_image: function refresh_image() {},
|
|
|
|
setup_ratings: function setup_ratings() {
|
|
var _ratings = this.frm.get_docinfo().rating || 0;
|
|
|
|
if (_ratings) {
|
|
this.ratings.removeClass("hide");
|
|
var rating_icons = frappe.render_template("rating_icons", { rating: _ratings, show_label: false });
|
|
this.ratings.find(".rating-icons").html(rating_icons);
|
|
}
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.set_user_image = function (frm) {
|
|
|
|
var image_section = frm.sidebar.image_section;
|
|
var image_field = frm.meta.image_field;
|
|
var image = frm.doc[image_field];
|
|
var title_image = frm.page.$title_area.find('.title-image');
|
|
|
|
image_section.toggleClass('hide', image_field ? false : true);
|
|
title_image.toggleClass('hide', image_field ? false : true);
|
|
|
|
if (!image_field) {
|
|
return;
|
|
}
|
|
|
|
if (image) {
|
|
image = window.cordova && image.indexOf('http') === -1 ? frappe.base_url + image : image;
|
|
|
|
image_section.find(".sidebar-image").css("background-image", 'url("' + image + '")').removeClass("hide");
|
|
|
|
image_section.find('.sidebar-standard-image').addClass('hide');
|
|
|
|
title_image.css('background-color', '').css("background-image", 'url("' + image + '")').html('');
|
|
} else {
|
|
image_section.find(".sidebar-image").css("background-image", null).addClass("hide");
|
|
|
|
var title = frm.get_title();
|
|
|
|
image_section.find('.sidebar-standard-image').removeClass('hide').find('.standard-image').css({ 'background-color': frappe.get_palette(title) }).html(frappe.get_abbr(title));
|
|
|
|
title_image.css("background-image", '').css({ 'background-color': frappe.get_palette(title) }).html(frappe.get_abbr(title));
|
|
}
|
|
};
|
|
|
|
frappe.ui.form.setup_user_image_event = function (frm) {
|
|
if (frm.meta.image_field) {
|
|
frappe.ui.form.on(frm.doctype, frm.meta.image_field, function (frm) {
|
|
frappe.ui.form.set_user_image(frm);
|
|
});
|
|
}
|
|
|
|
frm.sidebar.image_wrapper.on('click', function () {
|
|
var field = frm.get_field(frm.meta.image_field);
|
|
if (!field.$input) {
|
|
field.make_input();
|
|
}
|
|
field.$input.trigger('click');
|
|
});
|
|
};
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.Share = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
},
|
|
refresh: function refresh() {
|
|
this.render_sidebar();
|
|
},
|
|
render_sidebar: function render_sidebar() {
|
|
var me = this;
|
|
this.parent.empty();
|
|
|
|
var shared = this.shared || this.frm.get_docinfo().shared;
|
|
shared = shared.filter(function (d) {
|
|
return d;
|
|
});
|
|
var users = [];
|
|
for (var i = 0, l = shared.length; i < l; i++) {
|
|
var s = shared[i];
|
|
|
|
if (s.everyone) {
|
|
users.push({
|
|
icon: "octicon octicon-megaphone text-muted",
|
|
avatar_class: "avatar-empty share-doc-btn shared-with-everyone",
|
|
title: __("Shared with everyone")
|
|
});
|
|
} else {
|
|
var user_info = frappe.user_info(s.user);
|
|
users.push({
|
|
image: user_info.image,
|
|
fullname: user_info.fullname,
|
|
abbr: user_info.abbr,
|
|
color: user_info.color,
|
|
title: __("Shared with {0}", [user_info.fullname])
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!me.frm.doc.__islocal) {
|
|
users.push({
|
|
icon: "octicon octicon-plus text-muted",
|
|
avatar_class: "avatar-empty share-doc-btn",
|
|
title: __("Share")
|
|
});
|
|
}
|
|
|
|
this.parent.append(frappe.render_template("users_in_sidebar", { "users": users }));
|
|
this.parent.find(".avatar").on("click", function () {
|
|
me.frm.share_doc();
|
|
});
|
|
},
|
|
show: function show() {
|
|
var me = this;
|
|
var d = new frappe.ui.Dialog({
|
|
title: __("Share {0} with", [this.frm.doc.name])
|
|
});
|
|
|
|
this.dialog = d;
|
|
this.dirty = false;
|
|
|
|
frappe.call({
|
|
method: "frappe.share.get_users",
|
|
args: {
|
|
doctype: this.frm.doctype,
|
|
name: this.frm.doc.name
|
|
},
|
|
callback: function callback(r) {
|
|
me.render_shared(r.message || []);
|
|
}
|
|
});
|
|
|
|
$(d.body).html('<p class="text-muted">' + __("Loading...") + '</p>');
|
|
|
|
d.onhide = function () {
|
|
if (me.dirty) me.frm.reload_docinfo();
|
|
};
|
|
|
|
d.show();
|
|
},
|
|
render_shared: function render_shared(shared) {
|
|
if (shared) this.shared = shared;
|
|
var d = this.dialog;
|
|
$(d.body).empty();
|
|
|
|
var everyone = {};
|
|
$.each(this.shared, function (i, s) {
|
|
if (s && s.everyone) {
|
|
everyone = s;
|
|
}
|
|
});
|
|
|
|
$(frappe.render_template("set_sharing", { frm: this.frm, shared: this.shared, everyone: everyone })).appendTo(d.body);
|
|
|
|
if (frappe.model.can_share(null, this.frm)) {
|
|
this.make_user_input();
|
|
this.add_share_button();
|
|
this.set_edit_share_events();
|
|
} else {
|
|
$(d.body).find(".edit-share").prop("disabled", true);
|
|
}
|
|
},
|
|
make_user_input: function make_user_input() {
|
|
this.dialog.share_with = frappe.ui.form.make_control({
|
|
parent: $(this.dialog.body).find(".input-wrapper-add-share"),
|
|
df: {
|
|
fieldtype: "Link",
|
|
label: __("Share With"),
|
|
fieldname: "share_with",
|
|
options: "User",
|
|
filters: {
|
|
"user_type": "System User",
|
|
"name": ["!=", frappe.session.user]
|
|
}
|
|
},
|
|
only_input: true,
|
|
render_input: true
|
|
});
|
|
},
|
|
add_share_button: function add_share_button() {
|
|
var me = this,
|
|
d = this.dialog;
|
|
$(d.body).find(".btn-add-share").on("click", function () {
|
|
var user = d.share_with.get_value();
|
|
if (!user) {
|
|
return;
|
|
}
|
|
frappe.call({
|
|
method: "frappe.share.add",
|
|
args: {
|
|
doctype: me.frm.doctype,
|
|
name: me.frm.doc.name,
|
|
user: user,
|
|
read: $(d.body).find(".add-share-read").prop("checked") ? 1 : 0,
|
|
write: $(d.body).find(".add-share-write").prop("checked") ? 1 : 0,
|
|
share: $(d.body).find(".add-share-share").prop("checked") ? 1 : 0
|
|
},
|
|
btn: this,
|
|
callback: function callback(r) {
|
|
$.each(me.shared, function (i, s) {
|
|
if (s && s.user === r.message.user) {
|
|
delete me.shared[i];
|
|
}
|
|
});
|
|
me.dirty = true;
|
|
me.shared.push(r.message);
|
|
me.render_shared();
|
|
me.frm.shared.refresh();
|
|
}
|
|
});
|
|
});
|
|
},
|
|
set_edit_share_events: function set_edit_share_events() {
|
|
var me = this,
|
|
d = this.dialog;
|
|
$(d.body).find(".edit-share").on("click", function () {
|
|
var user = $(this).parents(".shared-user:first").attr("data-user") || "",
|
|
value = $(this).prop("checked") ? 1 : 0,
|
|
property = $(this).attr("name"),
|
|
everyone = cint($(this).parents(".shared-user:first").attr("data-everyone"));
|
|
|
|
frappe.call({
|
|
method: "frappe.share.set_permission",
|
|
args: {
|
|
doctype: me.frm.doctype,
|
|
name: me.frm.doc.name,
|
|
user: user,
|
|
permission_to: property,
|
|
value: value,
|
|
everyone: everyone
|
|
},
|
|
callback: function callback(r) {
|
|
var found = null;
|
|
$.each(me.shared, function (i, s) {
|
|
if (s && (s.user === user || everyone && s.everyone === 1)) {
|
|
if (!r.message) {
|
|
delete me.shared[i];
|
|
} else {
|
|
me.shared[i] = $.extend(s, r.message);
|
|
}
|
|
found = true;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (!found) {
|
|
me.shared.push(r.message);
|
|
}
|
|
|
|
me.dirty = true;
|
|
me.render_shared();
|
|
me.frm.shared.refresh();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.Viewers = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
},
|
|
refresh: function refresh(data_updated) {
|
|
var me = this;
|
|
this.parent.empty();
|
|
|
|
var viewers = this.frm.get_docinfo().viewers || {};
|
|
|
|
var users = [];
|
|
var new_users = [];
|
|
for (var i = 0, l = (viewers.current || []).length; i < l; i++) {
|
|
var username = viewers.current[i];
|
|
if (username === frappe.session.user) {
|
|
continue;
|
|
}
|
|
|
|
var user_info = frappe.user_info(username);
|
|
users.push({
|
|
image: user_info.image,
|
|
fullname: user_info.fullname,
|
|
abbr: user_info.abbr,
|
|
color: user_info.color,
|
|
title: __("{0} is currently viewing this document", [user_info.fullname])
|
|
});
|
|
|
|
if (viewers.new.indexOf(username) !== -1) {
|
|
new_users.push(user_info.fullname);
|
|
}
|
|
}
|
|
|
|
if (users.length) {
|
|
this.parent.parent().removeClass("hidden");
|
|
this.parent.append(frappe.render_template("users_in_sidebar", { "users": users }));
|
|
} else {
|
|
this.parent.parent().addClass("hidden");
|
|
}
|
|
|
|
if (data_updated && new_users.length) {
|
|
if (new_users.length === 1) {
|
|
frappe.show_alert(__("{0} is currently viewing this document", [new_users[0]]));
|
|
} else {
|
|
frappe.show_alert(__("{0} are currently viewing this document", [frappe.utils.comma_and(new_users)]));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.set_viewers = function (data) {
|
|
var doctype = data.doctype;
|
|
var docname = data.docname;
|
|
var past_viewers = (frappe.model.get_docinfo(doctype, docname).viewers || {}).past || [];
|
|
var viewers = data.viewers || [];
|
|
|
|
var new_viewers = viewers.filter(function (viewer) {
|
|
return !past_viewers.includes(viewer);
|
|
});
|
|
|
|
frappe.model.set_docinfo(doctype, docname, "viewers", {
|
|
past: past_viewers.concat(new_viewers),
|
|
new: new_viewers,
|
|
current: viewers
|
|
});
|
|
|
|
if (cur_frm.doc && cur_frm.doc.doctype === doctype && cur_frm.doc.name == docname) {
|
|
cur_frm.viewers.refresh(true);
|
|
}
|
|
};frappe.templates['form_footer'] = '<div class="form-footer"> <div class="after-save"> <div class="form-comments"></div> </div> <div class="pull-right scroll-to-top"> <a onclick="scroll(0,0)"><i class="fa fa-chevron-up text-muted"></i></a> </div> </div> ';
|
|
frappe.templates['timeline'] = '<div class="timeline"> <div class="timeline-head"> </div> <div class="timeline-new-email"> {% if(doctype === "Communication") { %} <button class="btn btn-default btn-reply-email btn-xs"> {%= __("Reply") %} </button> {% } else { %} <button class="btn btn-default btn-new-email btn-xs"> {%= __("New Email") %} </button> {% } %} </div> <div class="timeline-items"> </div> </div> ';
|
|
frappe.templates['timeline_item'] = '<div class="media timeline-item {% if (data.user_content) { %} user-content {% } else { %} notification-content {% } %}" data-doctype="{{ data.doctype }}" data-name="{%= data.name %}"> {% if (data.user_content) { %} <span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px"> {% if(data.user_info.image) { %} <div class="avatar-frame" style="background-image: url({%= data.user_info.image %})"></div> {% } else { %} <div class="standard-image" style="background-color: {{ data.user_info.color }}"> {{ data.user_info.abbr }}</div> {% } %} </span> {% } %} <div class="pull-left media-body"> <div class="media-content-wrapper"> <div class="action-btns"> {% if(data.delete) { %} <div class="pull-right hidden-xs close-btn-container"> <span class="small text-muted"> {%= data.delete %} </span> </div> {% } %} {% if(data.edit) { %} <div class="pull-right edit-btn-container"> <span class="small text-muted"> {%= data.edit %} </span> </div> {% } %} </div> {% if(data.communication_type==="Communication" || data.communication_type==="Feedback" || (data.communication_type==="Comment" && data.comment_type==="Comment")) { %} <div class="comment-header clearfix small {% if (data.edit || data.delete) { %} links-active {% } %}"> <span class="pull-left avatar avatar-small visible-xs"> {% if(data.user_info.image) { %} <div class="avatar-frame" style="background-image: url({%= data.user_info.image %})"></div> {% } else { %} <div class="standard-image" style="background-color: {{ data.user_info.color }}"> {{ data.user_info.abbr }}</div> {% } %} </span> <div class="asset-details"> <span class="author-wrap"> <i class="{%= data.icon %} hidden-xs fa-fw"></i> <span title="{%= data.comment_by %}">{%= data.fullname %}</span> </span> <span> {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} – <a href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}" class="text-muted"> <strong>{{ __(data.reference_doctype) }}</strong> {{ data.reference_name }} </a> {% } %} </span> {% if(in_list(["Communication", "Feedback"], data.communication_type)) { %} {% if (frappe.model.can_read(\'Communication\')) { %} <a href="#Form/{%= data.doctype %}/{%= data.name %}" class="text-muted"> {% } %} {% if (data.delivery_status) { if (in_list(["Sent", "Opened", "Clicked"], data.delivery_status)) { var indicator_class = "green"; } else if (data.delivery_status === "Sending") { var indicator_class = "orange"; } else { var indicator_class = "red"; } %} <span class="text-muted hidden-xs">–</span> <span class="indicator-right {%= indicator_class %} delivery-status-indicator" title="{%= data.delivery_status %}"><span class="hidden-xs"> {%= data.delivery_status %}</span></span> {% } else { %} {% if (frappe.model.can_read(\'Communication\')) { %} <span class="text-muted n-dash">–</span> {%= __("Details") %} {% } %} {% } %} {% if (frappe.model.can_read(\'Communication\')) { %} </a> {% } %} {% if (data.communication_medium === "Email" && data.sender !== frappe.session.user_email) { %} <a class="text-muted reply-link pull-right timeline-content-show" data-name="{%= data.name %}" title="{%= __("Reply") %}"><i class="octicon octicon-mail-reply"></i></a> {% } %} {% } %} <span class="text-muted commented-on hidden-xs"> – {%= data.comment_on %}</span> <span class="text-muted commented-on-small"> – {%= data.comment_on_small %}</span> <span class="comment-likes hidden-xs" data-liked-by=\'{{ JSON.stringify(data._liked_by) }}\'> <i class="octicon octicon-heart like-action {% if (!data.liked_by_user) { %} text-extra-muted not-liked {% } %} fa-fw" data-doctype="{%= data.doctype %}" data-name="{%= data.name %}"></i> <span class="likes-count text-muted"> {{ (data._liked_by || []).length }}</span> </span> </div> </div> <div class="reply timeline-content-show"> <div class="timeline-item-content"> {% if data.show_subject %} <p class="text-muted small"> <b>{{ __("Subject") }}:</b> {{ data.subject }}</p> <hr> {% endif %} {% if data.communication_type == "Feedback" && data.rating_icons %} <p class="text-muted small">{{ data.rating_icons }}</p> <hr> {% endif %} {%= data.content_html %} </div> {% if(data.attachments && data.attachments.length) { %} <div style="margin: 10px 0px"> {% $.each(data.attachments, function(i, a) { %} <div class="ellipsis"> <a href="{%= encodeURI(a.file_url).replace(/#/g, \'%23\') %}" class="text-muted small" target="_blank" rel="noopener noreferrer"> <i class="fa fa-paperclip"></i> {%= a.file_url.split("/").slice(-1)[0] %} {% if (a.is_private) { %} <i class="fa fa-lock text-warning"></i> {% } %} </a> </div> {% }); %} </div> {% } %} </div> {% } else if(in_list(["Assignment Completed", "Assigned", "Shared", "Unshared"], data.comment_type)) { %} <div class="small"> <i class="{%= data.icon %} fa-fw"></i> {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} <a href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}"> <strong>{{ __(data.reference_doctype) }}</strong> {{ data.reference_name }} </a> – {% } %} {% if(data.link_doctype && data.link_name) { %} <a href="#Form/{%= data.link_doctype %}/{%= data.link_name %}"> {% } %} {%= __(data.content) %} {% if(data.link_doctype && data.link_name) { %} </a> {% } %} <span class="text-muted commented-on" style="font-weight: normal;"> – {%= data.comment_on %}</span> </div> {% } else { %} <div class="small"> <i class="{%= data.icon %} fa-fw"></i> {% if (data.comment_type == "Like") { %} <span title="{%= data.comment_by %}"> {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} <a href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}"> <strong>{{ __(data.reference_doctype) }}</strong> {{ data.reference_name }} </a> – {% } %} {%= __("Liked by {0}", [data.fullname]) %} </span> {% } else { %} <b title="{{ data.comment_by }}">{%= data.fullname %}</b> {%= __(data.content) %} {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} – <a href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}"> <strong>{{ __(data.reference_doctype) }}</strong> {{ data.reference_name }} </a> {% } %} {% } %} <span class="text-muted commented-on" style="font-weight: normal;"> – {%= data.comment_on %}</span> </div> {% } %} </div> </div> </div> ';
|
|
|
|
|
|
frappe.ui.form.Footer = Class.extend({
|
|
init: function init(opts) {
|
|
var me = this;
|
|
$.extend(this, opts);
|
|
this.make();
|
|
this.make_comments();
|
|
|
|
$(this.frm.wrapper).on("render_complete", function () {
|
|
me.refresh();
|
|
});
|
|
},
|
|
make: function make() {
|
|
var me = this;
|
|
this.wrapper = $(frappe.render_template("form_footer", {})).appendTo(this.parent);
|
|
this.wrapper.find(".btn-save").click(function () {
|
|
me.frm.save('Save', null, this);
|
|
});
|
|
},
|
|
make_comments: function make_comments() {
|
|
this.frm.timeline = new frappe.ui.form.Timeline({
|
|
parent: this.wrapper.find(".form-comments"),
|
|
frm: this.frm
|
|
});
|
|
},
|
|
refresh: function refresh() {
|
|
if (this.frm.doc.__islocal) {
|
|
this.parent.addClass("hide");
|
|
} else {
|
|
this.parent.removeClass("hide");
|
|
this.frm.timeline.refresh();
|
|
}
|
|
}
|
|
});
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.Attachments = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.make();
|
|
},
|
|
make: function make() {
|
|
var me = this;
|
|
this.parent.find(".add-attachment").click(function () {
|
|
me.new_attachment();
|
|
});
|
|
this.add_attachment_wrapper = this.parent.find(".add_attachment").parent();
|
|
this.attachments_label = this.parent.find(".attachments-label");
|
|
},
|
|
max_reached: function max_reached() {
|
|
var n = Object.keys(this.get_attachments()).length;
|
|
|
|
if (n < this.frm.meta.max_attachments || !this.frm.meta.max_attachments) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
refresh: function refresh() {
|
|
var me = this;
|
|
|
|
if (this.frm.doc.__islocal) {
|
|
this.parent.toggle(false);
|
|
return;
|
|
}
|
|
this.parent.toggle(true);
|
|
this.parent.find(".attachment-row").remove();
|
|
|
|
var max_reached = this.max_reached();
|
|
this.add_attachment_wrapper.toggleClass("hide", !max_reached);
|
|
|
|
var attachments = this.get_attachments();
|
|
if (attachments.length) {
|
|
attachments.forEach(function (attachment) {
|
|
me.add_attachment(attachment);
|
|
});
|
|
} else {
|
|
this.attachments_label.removeClass("has-attachments");
|
|
}
|
|
},
|
|
get_attachments: function get_attachments() {
|
|
return this.frm.get_docinfo().attachments;
|
|
},
|
|
add_attachment: function add_attachment(attachment) {
|
|
var file_name = attachment.file_name;
|
|
var file_url = this.get_file_url(attachment);
|
|
var fileid = attachment.name;
|
|
if (!file_name) {
|
|
file_name = file_url;
|
|
}
|
|
|
|
var me = this;
|
|
var $attach = $(repl('<li class="attachment-row">\
|
|
<a class="close">×</a>\
|
|
%(lock_icon)s\
|
|
<a href="%(file_url)s" target="_blank" title="%(file_name)s" \
|
|
class="ellipsis" style="max-width: calc(100% - 43px);">\
|
|
<span>%(file_name)s</span></a>\
|
|
</li>', {
|
|
lock_icon: attachment.is_private ? '<i class="fa fa-lock fa-fw text-warning"></i> ' : "",
|
|
file_name: file_name,
|
|
file_url: frappe.urllib.get_full_url(file_url)
|
|
})).insertAfter(this.attachments_label.addClass("has-attachments"));
|
|
|
|
var $close = $attach.find(".close").data("fileid", fileid).click(function () {
|
|
var remove_btn = this;
|
|
frappe.confirm(__("Are you sure you want to delete the attachment?"), function () {
|
|
me.remove_attachment($(remove_btn).data("fileid"));
|
|
});
|
|
return false;
|
|
});
|
|
|
|
if (!frappe.model.can_write(this.frm.doctype, this.frm.name)) {
|
|
$close.remove();
|
|
}
|
|
},
|
|
get_file_url: function get_file_url(attachment) {
|
|
var file_url = attachment.file_url;
|
|
if (!file_url) {
|
|
if (attachment.file_name.indexOf('files/') === 0) {
|
|
file_url = '/' + attachment.file_name;
|
|
} else {
|
|
file_url = '/files/' + attachment.file_name;
|
|
}
|
|
}
|
|
|
|
return encodeURI(file_url).replace(/#/g, '%23');
|
|
},
|
|
get_file_id_from_file_url: function get_file_id_from_file_url(file_url) {
|
|
var fid;
|
|
$.each(this.get_attachments(), function (i, attachment) {
|
|
if (attachment.file_url === file_url) {
|
|
fid = attachment.name;
|
|
return false;
|
|
}
|
|
});
|
|
return fid;
|
|
},
|
|
remove_attachment_by_filename: function remove_attachment_by_filename(filename, callback) {
|
|
this.remove_attachment(this.get_file_id_from_file_url(filename), callback);
|
|
},
|
|
remove_attachment: function remove_attachment(fileid, _callback) {
|
|
if (!fileid) {
|
|
if (_callback) _callback();
|
|
return;
|
|
}
|
|
|
|
var me = this;
|
|
return frappe.call({
|
|
method: 'frappe.desk.form.utils.remove_attach',
|
|
args: {
|
|
fid: fileid,
|
|
dt: me.frm.doctype,
|
|
dn: me.frm.docname
|
|
},
|
|
callback: function callback(r, rt) {
|
|
if (r.exc) {
|
|
if (!r._server_messages) frappe.msgprint(__("There were errors"));
|
|
return;
|
|
}
|
|
me.remove_fileid(fileid);
|
|
me.frm.get_docinfo().communications.push(r.message);
|
|
me.frm.timeline.refresh();
|
|
if (_callback) _callback();
|
|
}
|
|
});
|
|
},
|
|
new_attachment: function new_attachment(fieldname) {
|
|
var me = this;
|
|
if (this.dialog) {
|
|
this.dialog.$wrapper.remove();
|
|
}
|
|
|
|
this.dialog = frappe.ui.get_upload_dialog({
|
|
"args": me.get_args(),
|
|
"callback": function callback(attachment, r) {
|
|
me.attachment_uploaded(attachment, r);
|
|
},
|
|
"max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null,
|
|
"max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null
|
|
});
|
|
},
|
|
get_args: function get_args() {
|
|
return {
|
|
from_form: 1,
|
|
doctype: this.frm.doctype,
|
|
docname: this.frm.docname
|
|
};
|
|
},
|
|
attachment_uploaded: function attachment_uploaded(attachment, r) {
|
|
this.dialog && this.dialog.hide();
|
|
this.update_attachment(attachment, r.message.comment);
|
|
|
|
if (this.fieldname) {
|
|
this.frm.set_value(this.fieldname, attachment.file_url);
|
|
}
|
|
},
|
|
update_attachment: function update_attachment(attachment, comment) {
|
|
if (attachment.name) {
|
|
this.add_to_attachments(attachment);
|
|
this.refresh();
|
|
if (comment) {
|
|
this.frm.get_docinfo().communications.push(comment);
|
|
this.frm.timeline.refresh();
|
|
}
|
|
}
|
|
},
|
|
add_to_attachments: function add_to_attachments(attachment) {
|
|
var form_attachments = this.get_attachments();
|
|
for (var i in form_attachments) {
|
|
if (form_attachments[i]["name"] === attachment.name) return;
|
|
}
|
|
form_attachments.push(attachment);
|
|
},
|
|
remove_fileid: function remove_fileid(fileid) {
|
|
var attachments = this.get_attachments();
|
|
var new_attachments = [];
|
|
$.each(attachments, function (i, attachment) {
|
|
if (attachment.name != fileid) {
|
|
new_attachments.push(attachment);
|
|
}
|
|
});
|
|
this.frm.get_docinfo().attachments = new_attachments;
|
|
this.refresh();
|
|
}
|
|
});
|
|
|
|
frappe.ui.get_upload_dialog = function (opts) {
|
|
var dialog = new frappe.ui.Dialog({
|
|
title: __('Upload Attachment'),
|
|
no_focus: true,
|
|
fields: [{ "fieldtype": "Section Break" }, { "fieldtype": "Link", "fieldname": "file", "label": __("Select uploaded file"), "options": "File" }, { "hidden": !opts.args.doctype || !frappe.boot.gsuite_enabled, "fieldtype": "Section Break", "label": __("GSuite Document") }, { "fieldtype": "Link", "fieldname": "gs_template", "label": __("Select template"), "options": "GSuite Templates", reqd: false, filters: { 'related_doctype': opts.args.doctype } }]
|
|
});
|
|
var btn = dialog.set_primary_action(__("Attach"));
|
|
btn.removeClass("btn-primary").addClass("btn-default");
|
|
|
|
dialog.show();
|
|
var upload_area = $('<div style="padding-bottom: 25px;"></div>').prependTo(dialog.body);
|
|
|
|
var fd = dialog.fields_dict;
|
|
|
|
$(fd.gs_template.input).change(function () {
|
|
opts.args.gs_template = fd.gs_template.get_value();
|
|
});
|
|
|
|
$(fd.file.input).change(function () {
|
|
frappe.call({
|
|
'method': 'frappe.client.get_value',
|
|
'args': {
|
|
'doctype': 'File',
|
|
'fieldname': ['file_url', 'file_name', 'is_private'],
|
|
'filters': {
|
|
'name': dialog.get_value("file")
|
|
}
|
|
},
|
|
callback: function callback(r) {
|
|
if (!r.message) return;
|
|
dialog.$wrapper.find('[name="file_url"]').val(r.message.file_url);
|
|
dialog.$wrapper.find('.private-file input').prop('checked', r.message.is_private);
|
|
opts.args.filename = r.message.file_name;
|
|
}
|
|
});
|
|
});
|
|
frappe.upload.make({
|
|
parent: upload_area,
|
|
args: opts.args,
|
|
callback: function callback(attachment, r) {
|
|
dialog.hide();
|
|
if (opts.callback) {
|
|
opts.callback(attachment, r);
|
|
}
|
|
},
|
|
on_select: function on_select() {
|
|
btn.removeClass("btn-default").addClass("btn-primary");
|
|
},
|
|
onerror: function onerror() {
|
|
dialog.hide();
|
|
},
|
|
btn: btn,
|
|
max_width: opts.max_width,
|
|
max_height: opts.max_height
|
|
});
|
|
|
|
return dialog;
|
|
};
|
|
|
|
frappe.provide('frappe.timeline');
|
|
|
|
frappe.ui.form.Timeline = Class.extend({
|
|
init: function init(opts) {
|
|
$.extend(this, opts);
|
|
this.make();
|
|
},
|
|
make: function make() {
|
|
var _this = this;
|
|
|
|
var me = this;
|
|
this.wrapper = $(frappe.render_template("timeline", { doctype: this.frm.doctype })).appendTo(this.parent);
|
|
|
|
this.list = this.wrapper.find(".timeline-items");
|
|
|
|
this.comment_area = new frappe.ui.CommentArea({
|
|
parent: this.wrapper.find('.timeline-head'),
|
|
mentions: this.get_usernames_for_mentions(),
|
|
on_submit: function on_submit(val) {
|
|
val && _this.insert_comment("Comment", val, _this.comment_area.button);
|
|
}
|
|
});
|
|
|
|
this.setup_editing_area();
|
|
|
|
this.setup_email_button();
|
|
|
|
this.list.on("click", ".toggle-blockquote", function () {
|
|
$(this).parent().siblings("blockquote").toggleClass("hidden");
|
|
});
|
|
|
|
this.setup_comment_like();
|
|
|
|
this.list.on("click", ".btn-more", function () {
|
|
var communications = me.get_communications();
|
|
frappe.call({
|
|
btn: this,
|
|
method: "frappe.desk.form.load.get_communications",
|
|
args: {
|
|
doctype: me.frm.doc.doctype,
|
|
name: me.frm.doc.name,
|
|
start: communications.length
|
|
},
|
|
callback: function callback(r) {
|
|
if (!r.exc) {
|
|
if (r.message) {
|
|
var new_communications = r.message;
|
|
var communications = me.get_communications().concat(new_communications);
|
|
frappe.model.set_docinfo(me.frm.doc.doctype, me.frm.doc.name, "communications", communications);
|
|
} else {
|
|
me.more = false;
|
|
}
|
|
|
|
me.refresh();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
setup_email_button: function setup_email_button() {
|
|
var me = this;
|
|
var selector = this.frm.doctype === "Communication" ? ".btn-reply-email" : ".btn-new-email";
|
|
this.email_button = this.wrapper.find(selector).on("click", function () {
|
|
var args = {
|
|
doc: me.frm.doc,
|
|
frm: me.frm,
|
|
recipients: me.get_recipient()
|
|
};
|
|
|
|
if (me.frm.doctype === "Communication") {
|
|
$.extend(args, {
|
|
txt: "",
|
|
last_email: me.frm.doc,
|
|
recipients: me.frm.doc.sender,
|
|
subject: __("Re: {0}", [me.frm.doc.subject])
|
|
});
|
|
} else {
|
|
$.extend(args, {
|
|
txt: frappe.markdown(me.comment_area.val())
|
|
});
|
|
}
|
|
new frappe.views.CommunicationComposer(args);
|
|
});
|
|
},
|
|
|
|
setup_editing_area: function setup_editing_area() {
|
|
this.$editing_area = $('<div class="timeline-editing-area">');
|
|
|
|
this.editing_area = new frappe.ui.CommentArea({
|
|
parent: this.$editing_area,
|
|
mentions: this.get_usernames_for_mentions(),
|
|
no_wrapper: true
|
|
});
|
|
|
|
this.editing_area.destroy();
|
|
},
|
|
|
|
refresh: function refresh(scroll_to_end) {
|
|
var me = this;
|
|
|
|
this.last_type = "Comment";
|
|
|
|
if (this.frm.doc.__islocal) {
|
|
this.wrapper.toggle(false);
|
|
return;
|
|
}
|
|
this.wrapper.toggle(true);
|
|
this.list.empty();
|
|
this.comment_area.val('');
|
|
|
|
var communications = this.get_communications(true);
|
|
|
|
communications.sort(function (a, b) {
|
|
return a.creation > b.creation ? -1 : 1;
|
|
}).filter(function (c) {
|
|
return c.content;
|
|
}).forEach(function (c) {
|
|
c.frm = me.frm;
|
|
me.render_timeline_item(c);
|
|
});
|
|
|
|
if (this.more === undefined && communications.length === 20) {
|
|
this.more = true;
|
|
}
|
|
|
|
if (this.more) {
|
|
$('<div class="timeline-item">\
|
|
<button class="btn btn-default btn-xs btn-more">More</button>\
|
|
</div>').appendTo(me.list);
|
|
}
|
|
|
|
me.render_timeline_item({
|
|
content: __("created"),
|
|
comment_type: "Created",
|
|
communication_type: "Comment",
|
|
sender: this.frm.doc.owner,
|
|
communication_date: this.frm.doc.creation,
|
|
creation: this.frm.doc.creation,
|
|
frm: this.frm
|
|
});
|
|
|
|
this.wrapper.find(".is-email").prop("checked", this.last_type === "Email").change();
|
|
|
|
this.frm.sidebar.refresh_comments();
|
|
|
|
this.frm.trigger('timeline_refresh');
|
|
},
|
|
|
|
render_timeline_item: function render_timeline_item(c) {
|
|
var me = this;
|
|
this.prepare_timeline_item(c);
|
|
var $timeline_item = $(frappe.render_template("timeline_item", { data: c, frm: this.frm })).appendTo(me.list).on("click", ".close", function () {
|
|
var name = $timeline_item.data('name');
|
|
me.delete_comment(name);
|
|
return false;
|
|
}).on('click', '.edit', function (e) {
|
|
e.preventDefault();
|
|
var name = $timeline_item.data('name');
|
|
|
|
if ($timeline_item.hasClass('is-editing')) {
|
|
me.editing_area.submit();
|
|
me.$editing_area.detach();
|
|
} else {
|
|
var $edit_btn = $(this);
|
|
var content = $timeline_item.find('.timeline-item-content').html();
|
|
|
|
$edit_btn.find('i').removeClass('octicon-pencil').addClass('octicon-check');
|
|
|
|
me.editing_area.setup_summernote();
|
|
me.editing_area.val(content);
|
|
me.editing_area.on_submit = function (value) {
|
|
me.editing_area.destroy();
|
|
value = value.trim();
|
|
|
|
c.content = value;
|
|
frappe.timeline.update_communication(c);
|
|
me.update_comment(name, value);
|
|
|
|
me.refresh();
|
|
};
|
|
|
|
$timeline_item.find('.timeline-item-content').hide();
|
|
$timeline_item.find('.timeline-content-show').append(me.$editing_area);
|
|
$timeline_item.addClass('is-editing');
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
if (c.communication_type == "Communication" && c.communication_medium === "Email") {
|
|
this.last_type = c.communication_medium;
|
|
this.add_reply_btn_event($timeline_item, c);
|
|
}
|
|
},
|
|
|
|
add_reply_btn_event: function add_reply_btn_event($timeline_item, c) {
|
|
var me = this;
|
|
$timeline_item.find(".reply-link").on("click", function () {
|
|
var name = $(this).attr("data-name");
|
|
var last_email = null;
|
|
|
|
me.get_communications().forEach(function (c) {
|
|
if (c.name == name) {
|
|
last_email = c;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
new frappe.views.CommunicationComposer({
|
|
doc: me.frm.doc,
|
|
txt: "",
|
|
frm: me.frm,
|
|
last_email: last_email
|
|
});
|
|
});
|
|
},
|
|
|
|
prepare_timeline_item: function prepare_timeline_item(c) {
|
|
if (!c.sender) c.sender = c.owner;
|
|
|
|
if (c.sender && c.sender.indexOf("<") !== -1) {
|
|
c.sender = c.sender.split("<")[1].split(">")[0];
|
|
}
|
|
|
|
c.user_info = frappe.user_info(c.sender);
|
|
|
|
c["delete"] = "";
|
|
c["edit"] = "";
|
|
if (c.communication_type == "Comment" && (c.comment_type || "Comment") === "Comment") {
|
|
if (frappe.model.can_delete("Communication")) {
|
|
c["delete"] = '<a class="close" title="Delete" href="#"><i class="octicon octicon-x"></i></a>';
|
|
}
|
|
|
|
if (frappe.user.name == c.sender || frappe.user.name == 'Administrator') {
|
|
c["edit"] = '<a class="edit" title="Edit" href="#"><i class="octicon octicon-pencil"></i></a>';
|
|
}
|
|
}
|
|
c.comment_on_small = comment_when(c.creation, true);
|
|
c.comment_on = comment_when(c.creation);
|
|
if (!c.fullname) {
|
|
c.fullname = c.sender_full_name || frappe.user.full_name(c.sender);
|
|
}
|
|
|
|
if (c.attachments && typeof c.attachments === "string") c.attachments = JSON.parse(c.attachments);
|
|
|
|
if (c.communication_type == "Comment" && !c.comment_type) {
|
|
c.comment_type = "Comment";
|
|
}
|
|
|
|
this.set_icon_and_color(c);
|
|
|
|
if (c.comment_type === "Workflow" || c.comment_type === "Label") {
|
|
c.comment_html = repl('<span class="label label-%(style)s">%(text)s</span>', {
|
|
style: frappe.utils.guess_style(c.content),
|
|
text: __(c.content)
|
|
});
|
|
} else {
|
|
if (c.communication_type == "Communication" && c.communication_medium == "Email") {
|
|
c.content = c.content.split("<!-- original-reply -->")[0];
|
|
c.content = frappe.utils.strip_original_content(c.content);
|
|
|
|
c.original_content = c.content;
|
|
c.content = frappe.utils.toggle_blockquote(c.content);
|
|
} else if (c.communication_type === "Feedback") {
|
|
c.content = frappe.utils.strip_original_content(c.content);
|
|
|
|
c.original_content = c.content;
|
|
c.content = frappe.utils.toggle_blockquote(c.content);
|
|
}
|
|
|
|
if (!frappe.utils.is_html(c.content)) {
|
|
c.content_html = frappe.markdown(__(c.content));
|
|
} else {
|
|
c.content_html = c.content;
|
|
c.content_html = frappe.utils.strip_whitespace(c.content_html);
|
|
c.content_html = c.content_html.replace(/</g, "<").replace(/>/g, ">");
|
|
}
|
|
|
|
if (c.comment_type === "Comment" && !c.content_html.match(/(^|\W)<b>(@\w+)<\/b>/)) {
|
|
c.content_html = c.content_html.replace(/(^|\W)(@\w+)/g, "$1<b>$2</b>");
|
|
}
|
|
|
|
if (this.is_communication_or_comment(c)) {
|
|
c.user_content = true;
|
|
if (!$.isArray(c._liked_by)) {
|
|
c._liked_by = JSON.parse(c._liked_by || "[]");
|
|
}
|
|
|
|
c.liked_by_user = c._liked_by.indexOf(frappe.session.user) !== -1;
|
|
}
|
|
}
|
|
|
|
c.content_html = frappe.dom.remove_script_and_style(c.content_html);
|
|
|
|
c.show_subject = false;
|
|
if (c.subject && c.communication_type === "Communication") {
|
|
if (this.frm.doc.subject && !this.frm.doc.subject.includes(c.subject)) {
|
|
c.show_subject = true;
|
|
} else if (this.frm.meta.title_field && !!this.frm.doc[this.frm.meta.title_field].includes(c.subject)) {
|
|
c.show_subject = true;
|
|
} else if (!this.frm.doc.name.includes(c.subject)) {
|
|
c.show_subject = true;
|
|
}
|
|
}
|
|
},
|
|
|
|
is_communication_or_comment: function is_communication_or_comment(c) {
|
|
return c.communication_type === "Communication" || c.communication_type === "Feedback" || c.communication_type === "Comment" && (c.comment_type === "Comment" || c.comment_type === "Relinked");
|
|
},
|
|
|
|
set_icon_and_color: function set_icon_and_color(c) {
|
|
if (c.communication_type == "Feedback") {
|
|
c.icon = "octicon octicon-comment-discussion";
|
|
c.rating_icons = frappe.render_template("rating_icons", { rating: c.rating, show_label: true });
|
|
c.color = "#f39c12";
|
|
} else {
|
|
c.icon = {
|
|
"Email": "octicon octicon-mail",
|
|
"Chat": "octicon octicon-comment-discussion",
|
|
"Phone": "octicon octicon-device-mobile",
|
|
"SMS": "octicon octicon-comment",
|
|
"Created": "octicon octicon-plus",
|
|
"Submitted": "octicon octicon-lock",
|
|
"Cancelled": "octicon octicon-x",
|
|
"Assigned": "octicon octicon-person",
|
|
"Assignment Completed": "octicon octicon-check",
|
|
"Comment": "octicon octicon-comment-discussion",
|
|
"Workflow": "octicon octicon-git-branch",
|
|
"Label": "octicon octicon-tag",
|
|
"Attachment": "octicon octicon-cloud-upload",
|
|
"Attachment Removed": "octicon octicon-trashcan",
|
|
"Shared": "octicon octicon-eye",
|
|
"Unshared": "octicon octicon-circle-slash",
|
|
"Like": "octicon octicon-heart",
|
|
"Edit": "octicon octicon-pencil",
|
|
"Relinked": "octicon octicon-check",
|
|
"Reply": "octicon octicon-mail-reply"
|
|
}[c.comment_type || c.communication_medium];
|
|
|
|
c.color = {
|
|
"Email": "#3498db",
|
|
"Chat": "#3498db",
|
|
"Phone": "#3498db",
|
|
"SMS": "#3498db",
|
|
"Created": "#1abc9c",
|
|
"Submitted": "#1abc9c",
|
|
"Cancelled": "#c0392b",
|
|
"Assigned": "#f39c12",
|
|
"Assignment Completed": "#16a085",
|
|
"Comment": "#f39c12",
|
|
"Workflow": "#2c3e50",
|
|
"Label": "#2c3e50",
|
|
"Attachment": "#7f8c8d",
|
|
"Attachment Removed": "#eee",
|
|
"Relinked": "#16a085",
|
|
"Reply": "#8d99a6"
|
|
}[c.comment_type || c.communication_medium];
|
|
|
|
c.icon_fg = {
|
|
"Attachment Removed": "#333"
|
|
}[c.comment_type || c.communication_medium];
|
|
}
|
|
if (!c.icon_fg) c.icon_fg = "#fff";
|
|
},
|
|
get_communications: function get_communications(with_versions) {
|
|
var docinfo = this.frm.get_docinfo(),
|
|
me = this,
|
|
out = [].concat(docinfo.communications);
|
|
|
|
if (with_versions) {
|
|
this.build_version_comments(docinfo, out);
|
|
}
|
|
return out;
|
|
},
|
|
build_version_comments: function build_version_comments(docinfo, out) {
|
|
var me = this;
|
|
|
|
docinfo.versions.forEach(function (version) {
|
|
if (!version.data) return;
|
|
var data = JSON.parse(version.data);
|
|
|
|
if (data.comment) {
|
|
out.push(me.get_version_comment(version, data.comment, data.comment_type));
|
|
return;
|
|
}
|
|
|
|
if (data.changed && data.changed.length) {
|
|
var parts = [];
|
|
data.changed.every(function (p) {
|
|
if (p[0] === 'docstatus') {
|
|
if (p[2] == 1) {
|
|
out.push(me.get_version_comment(version, __('submitted this document')));
|
|
} else if (p[2] == 2) {
|
|
out.push(me.get_version_comment(version, __('cancelled this document')));
|
|
}
|
|
} else {
|
|
|
|
var df = frappe.meta.get_docfield(me.frm.doctype, p[0], me.frm.docname);
|
|
|
|
if (df && !df.hidden) {
|
|
var field_display_status = frappe.perm.get_field_display_status(df, null, me.frm.perm);
|
|
if (field_display_status === 'Read' || field_display_status === 'Write') {
|
|
parts.push(__('{0} from {1} to {2}', [__(df.label), (frappe.ellipsis(p[1], 40) || '""').bold(), (frappe.ellipsis(p[2], 40) || '""').bold()]));
|
|
}
|
|
}
|
|
}
|
|
return parts.length < 3;
|
|
});
|
|
if (parts.length) {
|
|
out.push(me.get_version_comment(version, __("changed value of {0}", [parts.join(', ')])));
|
|
}
|
|
}
|
|
|
|
if (data.row_changed && data.row_changed.length) {
|
|
var parts = [],
|
|
count = 0;
|
|
data.row_changed.every(function (row) {
|
|
row[3].every(function (p) {
|
|
var df = me.frm.fields_dict[row[0]] && frappe.meta.get_docfield(me.frm.fields_dict[row[0]].grid.doctype, p[0], me.frm.docname);
|
|
|
|
if (df && !df.hidden) {
|
|
var field_display_status = frappe.perm.get_field_display_status(df, null, me.frm.perm);
|
|
|
|
if (field_display_status === 'Read' || field_display_status === 'Write') {
|
|
parts.push(__('{0} from {1} to {2} in row #{3}', [frappe.meta.get_label(me.frm.fields_dict[row[0]].grid.doctype, p[0]), (frappe.ellipsis(p[1], 40) || '""').bold(), (frappe.ellipsis(p[2], 40) || '""').bold(), row[1]]));
|
|
}
|
|
}
|
|
return parts.length < 3;
|
|
});
|
|
return parts.length < 3;
|
|
});
|
|
if (parts.length) {
|
|
out.push(me.get_version_comment(version, __("changed values for {0}", [parts.join(', ')])));
|
|
}
|
|
}
|
|
|
|
['added', 'removed'].forEach(function (key) {
|
|
if (data[key] && data[key].length) {
|
|
parts = (data[key] || []).map(function (p) {
|
|
var df = frappe.meta.get_docfield(me.frm.doctype, p[0], me.frm.docname);
|
|
if (df && !df.hidden) {
|
|
var field_display_status = frappe.perm.get_field_display_status(df, null, me.frm.perm);
|
|
|
|
if (field_display_status === 'Read' || field_display_status === 'Write') {
|
|
return frappe.meta.get_label(me.frm.doctype, p[0]);
|
|
}
|
|
}
|
|
});
|
|
parts = parts.filter(function (p) {
|
|
return p;
|
|
});
|
|
if (parts.length) {
|
|
out.push(me.get_version_comment(version, __("{0} rows for {1}", [__(key), parts.join(', ')])));
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
get_version_comment: function get_version_comment(version, text, comment_type) {
|
|
if (!comment_type) {
|
|
text = '<a href="#Form/Version/' + version.name + '">' + text + '</a>';
|
|
}
|
|
return {
|
|
comment_type: comment_type || 'Edit',
|
|
creation: version.creation,
|
|
owner: version.owner,
|
|
version_name: version.name,
|
|
sender: version.owner,
|
|
comment_by: version.owner,
|
|
content: text
|
|
};
|
|
},
|
|
|
|
insert_comment: function insert_comment(comment_type, comment, btn) {
|
|
var me = this;
|
|
return frappe.call({
|
|
method: "frappe.desk.form.utils.add_comment",
|
|
args: {
|
|
doc: {
|
|
doctype: "Communication",
|
|
communication_type: "Comment",
|
|
comment_type: comment_type || "Comment",
|
|
reference_doctype: this.frm.doctype,
|
|
reference_name: this.frm.docname,
|
|
content: comment,
|
|
sender: frappe.session.user
|
|
}
|
|
},
|
|
btn: btn,
|
|
callback: function callback(r) {
|
|
if (!r.exc) {
|
|
me.comment_area.val('');
|
|
frappe.utils.play_sound("click");
|
|
|
|
var comment = r.message;
|
|
var comments = me.get_communications();
|
|
var comment_exists = false;
|
|
for (var i = 0, l = comments.length; i < l; i++) {
|
|
if (comments[i].name == comment.name) {
|
|
comment_exists = true;
|
|
break;
|
|
}
|
|
}
|
|
if (comment_exists) {
|
|
return;
|
|
}
|
|
|
|
me.frm.get_docinfo().communications = comments.concat([r.message]);
|
|
me.refresh(true);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
delete_comment: function delete_comment(name) {
|
|
var me = this;
|
|
|
|
frappe.confirm(__('Delete comment?'), function () {
|
|
return frappe.call({
|
|
method: "frappe.client.delete",
|
|
args: {
|
|
doctype: "Communication",
|
|
name: name
|
|
},
|
|
callback: function callback(r) {
|
|
if (!r.exc) {
|
|
frappe.utils.play_sound("delete");
|
|
|
|
me.frm.get_docinfo().communications = $.map(me.frm.get_docinfo().communications, function (v) {
|
|
if (v.name == name) return null;else return v;
|
|
});
|
|
me.refresh(true);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
update_comment: function update_comment(name, content) {
|
|
return frappe.call({
|
|
method: 'frappe.client.set_value',
|
|
args: {
|
|
doctype: 'Communication',
|
|
name: name,
|
|
fieldname: 'content',
|
|
value: content
|
|
}, callback: function callback(r) {
|
|
if (!r.exc) {
|
|
frappe.utils.play_sound('click');
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
get_recipient: function get_recipient() {
|
|
if (this.frm.email_field) {
|
|
return this.frm.doc[this.frm.email_field];
|
|
} else {
|
|
return this.frm.doc.email_id || this.frm.doc.email || "";
|
|
}
|
|
},
|
|
|
|
get_last_email: function get_last_email(from_recipient) {
|
|
var last_email = null,
|
|
communications = this.frm.get_docinfo().communications,
|
|
email = this.get_recipient();
|
|
|
|
$.each(communications.sort(function (a, b) {
|
|
return a.creation > b.creation ? -1 : 1;
|
|
}), function (i, c) {
|
|
if (c.communication_type == 'Communication' && c.communication_medium == "Email") {
|
|
if (from_recipient) {
|
|
if (c.sender.indexOf(email) !== -1) {
|
|
last_email = c;
|
|
return false;
|
|
}
|
|
} else {
|
|
last_email = c;
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
|
|
return last_email;
|
|
},
|
|
|
|
get_usernames_for_mentions: function get_usernames_for_mentions() {
|
|
var valid_users = Object.keys(frappe.boot.user_info).filter(function (user) {
|
|
return !["Administrator", "Guest"].includes(user);
|
|
});
|
|
|
|
return valid_users.map(function (user) {
|
|
return frappe.boot.user_info[user].username;
|
|
});
|
|
},
|
|
|
|
setup_comment_like: function setup_comment_like() {
|
|
this.wrapper.on("click", ".comment-likes .octicon-heart", frappe.ui.click_toggle_like);
|
|
|
|
frappe.ui.setup_like_popover(this.wrapper, ".comment-likes");
|
|
}
|
|
});
|
|
|
|
$.extend(frappe.timeline, {
|
|
new_communication: function new_communication(communication) {
|
|
var docinfo = frappe.model.get_docinfo(communication.reference_doctype, communication.reference_name);
|
|
if (docinfo && docinfo.communications) {
|
|
var communications = docinfo.communications;
|
|
var communication_exists = false;
|
|
for (var i = 0, l = communications.length; i < l; i++) {
|
|
if (communications[i].name == communication.name) {
|
|
communication_exists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!communication_exists) {
|
|
docinfo.communications = communications.concat([communication]);
|
|
}
|
|
}
|
|
|
|
if (cur_frm.doctype === communication.reference_doctype && cur_frm.docname === communication.reference_name) {
|
|
cur_frm.timeline && cur_frm.timeline.refresh();
|
|
}
|
|
},
|
|
|
|
delete_communication: function delete_communication(communication) {
|
|
var docinfo = frappe.model.get_docinfo(communication.reference_doctype, communication.reference_name);
|
|
var index = frappe.timeline.index_of_communication(communication, docinfo);
|
|
if (index !== -1) {
|
|
docinfo.communications.splice(index, 1);
|
|
}
|
|
|
|
if (cur_frm.doctype === communication.reference_doctype && cur_frm.docname === communication.reference_name) {
|
|
cur_frm.timeline && cur_frm.timeline.refresh();
|
|
}
|
|
},
|
|
|
|
update_communication: function update_communication(communication) {
|
|
var docinfo = frappe.model.get_docinfo(communication.reference_doctype, communication.reference_name);
|
|
var index = frappe.timeline.index_of_communication(communication, docinfo);
|
|
|
|
if (index !== -1) {
|
|
$.extend(docinfo.communications[index], communication);
|
|
}
|
|
|
|
if (cur_frm.doctype === communication.reference_doctype && cur_frm.docname === communication.reference_name) {
|
|
cur_frm.timeline && cur_frm.timeline.refresh();
|
|
}
|
|
},
|
|
|
|
index_of_communication: function index_of_communication(communication, docinfo) {
|
|
var index = -1;
|
|
|
|
if (docinfo && docinfo.communications) {
|
|
var communications = docinfo.communications;
|
|
|
|
for (var i = 0, l = communications.length; i < l; i++) {
|
|
if (communications[i].name == communication.name) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return index;
|
|
}
|
|
});
|
|
|
|
frappe.provide("frappe.ui.form");
|
|
|
|
frappe.ui.form.AssignTo = Class.extend({
|
|
init: function init(opts) {
|
|
var me = this;
|
|
|
|
$.extend(this, opts);
|
|
this.btn = this.parent.find(".add-assignment").on("click", function () {
|
|
me.add();
|
|
});
|
|
this.btn_wrapper = this.btn.parent();
|
|
|
|
this.refresh();
|
|
},
|
|
refresh: function refresh() {
|
|
if (this.frm.doc.__islocal) {
|
|
this.parent.toggle(false);
|
|
return;
|
|
}
|
|
this.parent.toggle(true);
|
|
this.render(this.frm.get_docinfo().assignments);
|
|
},
|
|
render: function render(d) {
|
|
var me = this;
|
|
this.frm.get_docinfo().assignments = d;
|
|
this.parent.find(".assignment-row").remove();
|
|
|
|
if (me.primary_action) {
|
|
me.primary_action.remove();
|
|
me.primary_action = null;
|
|
}
|
|
|
|
if (this.dialog) {
|
|
this.dialog.hide();
|
|
}
|
|
|
|
if (d && d.length) {
|
|
for (var i = 0; i < d.length; i++) {
|
|
var info = frappe.user_info(d[i].owner);
|
|
info.assign_to_name = d[i].name;
|
|
info.owner = d[i].owner;
|
|
info.avatar = frappe.avatar(d[i].owner);
|
|
info.description = d[i].description || "";
|
|
|
|
info._fullname = info.fullname;
|
|
if (info.fullname.length > 10) {
|
|
info._fullname = info.fullname.substr(0, 10) + '...';
|
|
}
|
|
|
|
$(repl('<li class="assignment-row">\
|
|
<a class="close" data-owner="%(owner)s">×</a>\
|
|
%(avatar)s\
|
|
<span><a href="#Form/ToDo/%(assign_to_name)s">%(_fullname)s</a></span>\
|
|
</li>', info)).insertBefore(this.parent.find('.add-assignment'));
|
|
|
|
if (d[i].owner === frappe.session.user) {
|
|
me.primary_action = this.frm.page.add_menu_item(__("Assignment Complete"), function () {
|
|
me.remove(frappe.session.user);
|
|
}, "fa fa-check", "btn-success");
|
|
}
|
|
|
|
if (!(d[i].owner === frappe.session.user || me.frm.perm[0].write)) {
|
|
me.parent.find('a.close').remove();
|
|
}
|
|
}
|
|
|
|
this.parent.find('a.close').click(function () {
|
|
me.remove($(this).attr('data-owner'));
|
|
return false;
|
|
});
|
|
} else {}
|
|
},
|
|
add: function add() {
|
|
var me = this;
|
|
|
|
if (this.frm.is_new()) {
|
|
frappe.throw(__("Please save the document before assignment"));
|
|
return;
|
|
}
|
|
|
|
if (!me.dialog) {
|
|
me.dialog = new frappe.ui.form.AssignToDialog({
|
|
obj: me,
|
|
method: 'frappe.desk.form.assign_to.add',
|
|
doctype: me.frm.doctype,
|
|
docname: me.frm.docname,
|
|
callback: function callback(r) {
|
|
me.render(r.message);
|
|
}
|
|
});
|
|
}
|
|
me.dialog.clear();
|
|
|
|
if (me.frm.meta.title_field) {
|
|
me.dialog.set_value("description", me.frm.doc[me.frm.meta.title_field]);
|
|
}
|
|
|
|
me.dialog.show();
|
|
},
|
|
remove: function remove(owner) {
|
|
var me = this;
|
|
|
|
if (this.frm.is_new()) {
|
|
frappe.throw(__("Please save the document before removing assignment"));
|
|
return;
|
|
}
|
|
|
|
frappe.call({
|
|
method: 'frappe.desk.form.assign_to.remove',
|
|
args: {
|
|
doctype: me.frm.doctype,
|
|
name: me.frm.docname,
|
|
assign_to: owner
|
|
},
|
|
callback: function callback(r, rt) {
|
|
me.render(r.message);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
frappe.ui.form.AssignToDialog = Class.extend({
|
|
init: function init(opts) {
|
|
var me = this;
|
|
$.extend(me, new frappe.ui.Dialog({
|
|
title: __('Add to To Do'),
|
|
fields: [{ fieldtype: 'Link', fieldname: 'assign_to', options: 'User',
|
|
label: __("Assign To"), reqd: true, filters: { 'user_type': 'System User' } }, { fieldtype: 'Check', fieldname: 'myself', label: __("Assign to me"), "default": 0 }, { fieldtype: 'Small Text', fieldname: 'description', label: __("Comment"), reqd: true }, { fieldtype: 'Section Break' }, { fieldtype: 'Column Break' }, { fieldtype: 'Date', fieldname: 'date', label: __("Complete By") }, { fieldtype: 'Check', fieldname: 'notify',
|
|
label: __("Notify by Email"), "default": 1 }, { fieldtype: 'Column Break' }, { fieldtype: 'Select', fieldname: 'priority', label: __("Priority"),
|
|
options: [{ value: 'Low', label: __('Low') }, { value: 'Medium', label: __('Medium') }, { value: 'High', label: __('High') }],
|
|
'default': 'Medium' }],
|
|
primary_action: function primary_action() {
|
|
frappe.ui.add_assignment(opts, me);
|
|
},
|
|
primary_action_label: __("Add")
|
|
}));
|
|
|
|
me.fields_dict.assign_to.get_query = "frappe.core.doctype.user.user.user_query";
|
|
|
|
var myself = me.get_input("myself").on("click", function () {
|
|
me.toggle_myself(this);
|
|
});
|
|
me.toggle_myself(myself);
|
|
},
|
|
toggle_myself: function toggle_myself(myself) {
|
|
var me = this;
|
|
if ($(myself).prop("checked")) {
|
|
me.set_value("assign_to", frappe.session.user);
|
|
me.set_value("notify", 0);
|
|
me.get_field("notify").$wrapper.toggle(false);
|
|
me.get_field("assign_to").$wrapper.toggle(false);
|
|
} else {
|
|
me.set_value("assign_to", "");
|
|
me.set_value("notify", 1);
|
|
me.get_field("notify").$wrapper.toggle(true);
|
|
me.get_field("assign_to").$wrapper.toggle(true);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
frappe.ui.add_assignment = function (opts, dialog) {
|
|
var assign_to = opts.obj.dialog.fields_dict.assign_to.get_value();
|
|
var args = opts.obj.dialog.get_values();
|
|
if (args && assign_to) {
|
|
return frappe.call({
|
|
method: opts.method,
|
|
args: $.extend(args, {
|
|
doctype: opts.doctype,
|
|
name: opts.docname,
|
|
assign_to: assign_to,
|
|
bulk_assign: opts.bulk_assign || false,
|
|
re_assign: opts.re_assign || false
|
|
}),
|
|
callback: function callback(r, rt) {
|
|
if (!r.exc) {
|
|
if (opts.callback) {
|
|
opts.callback(r);
|
|
}
|
|
dialog && dialog.hide();
|
|
}
|
|
},
|
|
btn: this
|
|
});
|
|
}
|
|
};
|
|
|
|
frappe.provide('frappe.ui.form');
|
|
|
|
frappe.ui.form.make_quick_entry = function (doctype, after_insert) {
|
|
var trimmed_doctype = doctype.replace(/ /g, '');
|
|
var controller_name = "QuickEntryForm";
|
|
|
|
if (frappe.ui.form[trimmed_doctype + "QuickEntryForm"]) {
|
|
controller_name = trimmed_doctype + "QuickEntryForm";
|
|
}
|
|
|
|
frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert);
|
|
return frappe.quick_entry.setup();
|
|
};
|
|
|
|
frappe.ui.form.QuickEntryForm = Class.extend({
|
|
init: function init(doctype, after_insert) {
|
|
this.doctype = doctype;
|
|
this.after_insert = after_insert;
|
|
},
|
|
|
|
setup: function setup() {
|
|
var _this = this;
|
|
|
|
var me = this;
|
|
return new Promise(function (resolve) {
|
|
frappe.model.with_doctype(_this.doctype, function () {
|
|
me.set_meta_and_mandatory_fields();
|
|
if (me.is_quick_entry()) {
|
|
me.render_dialog();
|
|
resolve(me);
|
|
} else {
|
|
frappe.quick_entry = null;
|
|
frappe.set_route('Form', me.doctype, me.doc.name).then(function () {
|
|
return resolve(me);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
set_meta_and_mandatory_fields: function set_meta_and_mandatory_fields() {
|
|
this.mandatory = $.map(frappe.get_meta(this.doctype).fields, function (d) {
|
|
return d.reqd || d.bold && !d.read_only ? d : null;
|
|
});
|
|
this.meta = frappe.get_meta(this.doctype);
|
|
this.doc = frappe.model.get_new_doc(this.doctype, null, null, true);
|
|
},
|
|
|
|
is_quick_entry: function is_quick_entry() {
|
|
if (this.meta.quick_entry != 1) {
|
|
return false;
|
|
}
|
|
|
|
if (this.too_many_mandatory_fields() || this.has_child_table()) {
|
|
return false;
|
|
}
|
|
|
|
this.validate_for_prompt_autoname();
|
|
return true;
|
|
},
|
|
|
|
too_many_mandatory_fields: function too_many_mandatory_fields() {
|
|
if (this.mandatory.length > 7) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
has_child_table: function has_child_table() {
|
|
if ($.map(this.mandatory, function (d) {
|
|
return d.fieldtype === 'Table' ? d : null;
|
|
}).length) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
validate_for_prompt_autoname: function validate_for_prompt_autoname() {
|
|
if (this.meta.autoname && this.meta.autoname.toLowerCase() === 'prompt') {
|
|
this.mandatory = [{ fieldname: '__name', label: __('{0} Name', [this.meta.name]),
|
|
reqd: 1, fieldtype: 'Data' }].concat(this.mandatory);
|
|
}
|
|
},
|
|
|
|
render_dialog: function render_dialog() {
|
|
var me = this;
|
|
this.dialog = new frappe.ui.Dialog({
|
|
title: __("New {0}", [__(this.doctype)]),
|
|
fields: this.mandatory
|
|
});
|
|
this.dialog.doc = this.doc;
|
|
|
|
this.dialog.refresh();
|
|
|
|
this.register_primary_action();
|
|
this.render_edit_in_full_page_link();
|
|
|
|
this.dialog.wrapper.keydown(function (e) {
|
|
if ((e.ctrlKey || e.metaKey) && e.which == 13) {
|
|
if (!frappe.request.ajax_count) {
|
|
me.dialog.get_primary_btn().trigger("click");
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.dialog.onhide = function () {
|
|
return frappe.quick_entry = null;
|
|
};
|
|
this.dialog.show();
|
|
this.set_defaults();
|
|
},
|
|
|
|
register_primary_action: function register_primary_action() {
|
|
var me = this;
|
|
this.dialog.set_primary_action(__('Save'), function () {
|
|
if (me.dialog.working) {
|
|
return;
|
|
}
|
|
var data = me.dialog.get_values();
|
|
|
|
if (data) {
|
|
me.dialog.working = true;
|
|
me.insert();
|
|
}
|
|
});
|
|
},
|
|
|
|
insert: function insert() {
|
|
var me = this;
|
|
return new Promise(function (resolve) {
|
|
me.update_doc();
|
|
frappe.call({
|
|
method: "frappe.client.insert",
|
|
args: {
|
|
doc: me.dialog.doc
|
|
},
|
|
callback: function callback(r) {
|
|
me.dialog.hide();
|
|
|
|
frappe.model.clear_doc(me.dialog.doc.doctype, me.dialog.doc.name);
|
|
me.dialog.doc = r.message;
|
|
if (frappe._from_link) {
|
|
frappe.ui.form.update_calling_link(me.dialog.doc);
|
|
} else {
|
|
if (me.after_insert) {
|
|
me.after_insert(me.dialog.doc);
|
|
} else {
|
|
me.open_from_if_not_list();
|
|
}
|
|
}
|
|
},
|
|
error: function error() {
|
|
me.open_doc();
|
|
},
|
|
always: function always() {
|
|
me.dialog.working = false;
|
|
resolve(me.dialog.doc);
|
|
},
|
|
freeze: true
|
|
});
|
|
});
|
|
},
|
|
|
|
open_from_if_not_list: function open_from_if_not_list() {
|
|
var route = frappe.get_route();
|
|
var doc = this.dialog.doc;
|
|
if (route && !(route[0] === 'List' && route[1] === doc.doctype)) {
|
|
frappe.set_route('Form', doc.doctype, doc.name);
|
|
}
|
|
},
|
|
|
|
update_doc: function update_doc() {
|
|
var me = this;
|
|
var data = this.dialog.get_values(true);
|
|
$.each(data, function (key, value) {
|
|
if (key === '__name') {
|
|
me.dialog.doc.name = value;
|
|
} else {
|
|
if (!is_null(value)) {
|
|
me.dialog.doc[key] = value;
|
|
}
|
|
}
|
|
});
|
|
return this.dialog.doc;
|
|
},
|
|
|
|
open_doc: function open_doc() {
|
|
this.dialog.hide();
|
|
this.update_doc();
|
|
frappe.set_route('Form', this.doctype, this.doc.name);
|
|
},
|
|
|
|
render_edit_in_full_page_link: function render_edit_in_full_page_link() {
|
|
var me = this;
|
|
var $link = $('<div class="text-muted small" style="padding-left: 10px; padding-top: 15px;">' + __("Ctrl+enter to save") + ' | <a class="edit-full">' + __("Edit in full page") + '</a></div>').appendTo(this.dialog.body);
|
|
|
|
$link.find('.edit-full').on('click', function () {
|
|
me.open_doc();
|
|
});
|
|
},
|
|
|
|
set_defaults: function set_defaults() {
|
|
var me = this;
|
|
|
|
$.each(this.dialog.fields_dict, function (fieldname, field) {
|
|
field.doctype = me.doc.doctype;
|
|
field.docname = me.doc.name;
|
|
|
|
if (!is_null(me.doc[fieldname])) {
|
|
field.set_input(me.doc[fieldname]);
|
|
}
|
|
});
|
|
}
|
|
}); |