frappe.templates['grid_form'] = '
{%= __("Editing Row") %} #
'; frappe.templates['grid_body'] = '
{%= __("No Data") %}
'; frappe.templates['print_layout'] = '
'; frappe.templates['users_in_sidebar'] = '{% for (var i=0, l=users.length; i < l; i++) { var u = users[i]; %} {% if (u.icon) { %} {% } else if(u.image) { %} {{ u.fullname }} {% } else { %}
{{ u.abbr.substr(0,1) }}
{% } %}
{% } %} '; frappe.templates['set_sharing'] = '
{%= __("User") %}
{%= __("Can Read") %}
{%= __("Can Write") %}
{%= __("Can Share") %}
{% for (var i=0, l=shared.length; i < l; i++) { var s = shared[i]; %} {% if(s && !s.everyone) { %}
{%= s.user %}
{% } %} {% } %} {% if(frappe.model.can_share(null, frm)) { %}
{%= __("Share this document with") %}
{%= __("Can Read") %}
{%= __("Can Write") %}
{%= __("Can Share") %}

{% } %}
'; frappe.templates['form_sidebar'] = ' {% if frm.meta.beta %} {% endif %} {% if(frappe.get_form_sidebar_extension) { %} {{ frappe.get_form_sidebar_extension() }} {% } %} '; frappe.templates['form_dashboard'] = '
'; frappe.templates['form_document_flow'] = '
{% for dt in doctypes %}
{{ __(dt) }}
{% endfor %}
'; frappe.templates['form_links'] = '
{% for (var i=0; i < transactions.length; i++) { %} {% if((i % 2)===0) { %}
{% } %}
{{ transactions[i].label }}
{% for (var j=0; j < transactions[i].items.length; j++) { var doctype = transactions[i].items[j]; %} {% } %}
{% if((i % 2)===1) { %}
{% } %} {% } %} {% if((i % 2)===0) { %}
{% } %} '; 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: $('
').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 = $('
').appendTo(this.layout_main); this.body = $('
').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") + '' + __("Refresh") + '', "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('%(label)s', { 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('
' + text + '
'); } else { this.clear_headline(); } }, add_section: function add_section(html) { return $('
' + html + '
').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 = $('
').appendTo(progress_chart); $.each(percent, function (i, opts) { $(repl('
', opts)).appendTo(progress); }); if (message) { $('

' + message + '

').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 = $('
').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 = $('
' + label + '
').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 = $('').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 + '

"; 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: '
' + e.stack + '
' }); } } 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 = $('').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 = ''; this.columns = {}; this.columns_list = []; $.extend(this, opts); this.make(); }, make: function make() { var me = this; this.wrapper = $('
').appendTo(this.parent).data("grid_row", this); this.row = $('
').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 = $('
' + this.row_check_html + '
').appendTo(this.row); } this.row_index.find('span').html(this.doc.idx); } this.row_display = $('
' + +'
').appendTo(this.row).html(frappe.render(this.grid.template, { doc: this.doc ? frappe.get_format_helper(this.doc) : null, frm: this.frm, row: this })); }, render_row: function render_row(refresh) { var me = this; this.set_row_index(); if (!this.row_index) { var txt = this.doc ? this.doc.idx : " "; this.row_index = $('
\n\t\t\t\t\t' + this.row_check_html + '\n\t\t\t\t' + txt + '
').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 = $('\ ').appendTo($('
').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 = $('
').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 = $('
').appendTo($col).toggle(false); $col.static_area = $('
').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 = $('
').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("
\n\t\t\t\t" + __("Loading") + "...\n\t\t\t
"); 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 "
\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 = $('
').append($item); return $item_container[0].outerHTML; }).join("") + "\n\t\t\t\t
"; }); } $(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 "
\n\t\t
\n\t\t\t" + heading + "\n\t\t
"; } }, { key: "make_doc_row", value: function make_doc_row(doc, doctype) { return "
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t" + doc.name + "\n\t\t\t\t
\n\t\t\t
\n\t\t
"; } }]); 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("

" + __("Current status") + ": " + state.bold() + "

" + "

" + __("Document is only editable by users of role") + ": " + frappe.workflow.get_document_state(me.frm.doctype, state).allow_edit.bold() + "

" + "

" + __("Next actions") + ": " + next_html + "

" + (me.frm.doc.__islocal ? "
" + __("Workflow will start after saving.") + "
" : "") + "

" + __("Note: Other permission rules may also apply") + "

").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('
' + __("Warning: This Print Format is in old style and cannot be generated via the API.") + '
' + 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 = $('').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}", ["" + frappe.user.full_name(this.frm.doc.modified_by) + "", "
" + comment_when(this.frm.doc.modified)])); this.sidebar.find(".created-by").html(__("{0} created this {1}", ["" + frappe.user.full_name(this.frm.doc.owner) + "", "
" + 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 $('').html(label).appendTo($('
  • ').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('

    ' + __("Loading...") + '

    '); 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'] = '
    '; frappe.templates['timeline'] = '
    {% if(doctype === "Communication") { %} {% } else { %} {% } %}
    '; frappe.templates['timeline_item'] = '
    {% if (data.user_content) { %} {% } %}
    {% if(data.delete) { %} {% } %} {% if(data.edit) { %}
    {%= data.edit %}
    {% } %}
    {% if(data.communication_type==="Communication" || data.communication_type==="Feedback" || (data.communication_type==="Comment" && data.comment_type==="Comment")) { %}
    {% if data.show_subject %}

    {{ __("Subject") }}: {{ data.subject }}


    {% endif %} {% if data.communication_type == "Feedback" && data.rating_icons %}

    {{ data.rating_icons }}


    {% endif %} {%= data.content_html %}
    {% if(data.attachments && data.attachments.length) { %}
    {% $.each(data.attachments, function(i, a) { %} {% }); %}
    {% } %}
    {% } else if(in_list(["Assignment Completed", "Assigned", "Shared", "Unshared"], data.comment_type)) { %}
    {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} {{ __(data.reference_doctype) }} {{ data.reference_name }} – {% } %} {% if(data.link_doctype && data.link_name) { %} {% } %} {%= __(data.content) %} {% if(data.link_doctype && data.link_name) { %} {% } %} – {%= data.comment_on %}
    {% } else { %}
    {% if (data.comment_type == "Like") { %} {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} {{ __(data.reference_doctype) }} {{ data.reference_name }} – {% } %} {%= __("Liked by {0}", [data.fullname]) %} {% } else { %} {%= data.fullname %} {%= __(data.content) %} {% if (data.timeline_doctype===data.frm.doc.doctype && data.timeline_name===data.frm.doc.name) { %} – {{ __(data.reference_doctype) }} {{ data.reference_name }} {% } %} {% } %} – {%= data.comment_on %}
    {% } %}
    '; 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('
  • \ ×\ %(lock_icon)s\ \ %(file_name)s\
  • ', { lock_icon: attachment.is_private ? ' ' : "", 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 = $('
    ').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 = $('
    '); 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) { $('
    \ \
    ').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"] = ''; } if (frappe.user.name == c.sender || frappe.user.name == 'Administrator') { c["edit"] = ''; } } 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('%(text)s', { 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("")[0]; c.content = frappe.utils.strip_original_content(c.content); c.original_content = c.content; c.content = frappe.utils.toggle_blockquote(c.content); } else if (c.communication_type === "Feedback") { c.content = frappe.utils.strip_original_content(c.content); c.original_content = c.content; c.content = frappe.utils.toggle_blockquote(c.content); } if (!frappe.utils.is_html(c.content)) { c.content_html = frappe.markdown(__(c.content)); } else { c.content_html = c.content; c.content_html = frappe.utils.strip_whitespace(c.content_html); c.content_html = c.content_html.replace(/</g, "<").replace(/>/g, ">"); } if (c.comment_type === "Comment" && !c.content_html.match(/(^|\W)(@\w+)<\/b>/)) { c.content_html = c.content_html.replace(/(^|\W)(@\w+)/g, "$1$2"); } 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 = '' + text + ''; } 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('
  • \ ×\ %(avatar)s\ %(_fullname)s\
  • ', 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 = $('
    ' + __("Ctrl+enter to save") + ' | ' + __("Edit in full page") + '
    ').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]); } }); } });