frappe_docker/frappe-bench/sites/assets/js/form.min.js
2017-07-31 15:51:51 +05:30

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> &ndash; <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 : "&nbsp;";
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) { %} &ndash; <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">&ndash;</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">&ndash;</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"> &ndash; {%= data.comment_on %}</span> <span class="text-muted commented-on-small"> &ndash; {%= 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> &ndash; {% } %} {% 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;"> &ndash; {%= 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> &ndash; {% } %} {%= __("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) { %} &ndash; <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;"> &ndash; {%= 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">&times;</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(/&lt;/g, "<").replace(/&gt;/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">&times;</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]);
}
});
}
});