// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com) // // MIT License (MIT) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // /* Form page structure + this.parent (either FormContainer or Dialog) + this.wrapper + this.toolbar + this.form_wrapper + this.main + this.head + this.body + this.layout + this.footer + this.sidebar + this.print_wrapper + this.head */ wn.provide('_f'); wn.provide('wn.ui.form'); wn.ui.form.Controller = Class.extend({ init: function(opts) { $.extend(this, opts); this.setup && this.setup(); } }); _f.frms = {}; _f.Frm = function(doctype, parent, in_form) { this.docname = ''; this.doctype = doctype; this.display = 0; this.refresh_if_stale_for = 120; var me = this; this.last_view_is_edit = {}; this.opendocs = {}; this.sections = []; this.grids = []; this.cscript = new wn.ui.form.Controller({frm:this}); this.pformat = {}; this.fetch_dict = {}; this.parent = parent; this.tinymce_id_list = []; this.setup_meta(doctype); // show in form instead of in dialog, when called using url (router.js) this.in_form = in_form ? true : false; // notify on rename var me = this; $(document).bind('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') { msgprint('Allowing DocType, DocType. Be careful!') } else if(this.doctype=='DocType') { if (wn.views.formview[docname] || wn.pages['List/'+docname]) { msgprint("Cannot open DocType when its instance is open") throw 'doctype open conflict' } } else { if (wn.views.formview.DocType && wn.views.formview.DocType.frm.opendocs[this.doctype]) { msgprint("Cannot open instance when its DocType is open") throw 'doctype open conflict' } } } _f.Frm.prototype.setup = function() { var me = this; this.fields = []; this.fields_dict = {}; this.state_fieldname = wn.workflow.get_state_fieldname(this.doctype); // wrapper this.wrapper = this.parent; wn.ui.make_app_page({ parent: this.wrapper, single_column: true }); this.appframe = this.wrapper.appframe; this.layout_main = $(this.wrapper).find(".layout-main").get(0); this.toolbar = new wn.ui.form.Toolbar({ frm: this, appframe: this.appframe }) // create area for print fomrat this.setup_print_layout(); // 2 column layout this.setup_std_layout(); // client script must be called after "setup" - there are no fields_dict attached to the frm otherwise this.setup_client_script(); this.setup_header(); this.setup_done = true; } _f.Frm.prototype.setup_print_layout = function() { var me = this; this.print_wrapper = $('
\
\ \ \
\
\ \
').appendTo(this.layout_main).get(0); $(this.print_wrapper).find(".btn-edit").click(function() { me.edit_doc(); return false; }) this.$print_view_select = $(this.print_wrapper).find(".preview-select") .add_options(this.print_formats) .val(this.print_formats[0]) .change(function() { me.refresh_print_layout(); }) //appframe.add_ripped_paper_effect(this.print_wrapper); this.print_body = $(this.print_wrapper).find(".print-format-area").get(0); } _f.Frm.prototype.onhide = function() { if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect(); } _f.Frm.prototype.setup_std_layout = function() { this.form_wrapper = $('
').appendTo(this.layout_main).get(0); $parent = $(this.form_wrapper); this.head = $parent.find(".layout-appframe").get(0); this.main = this.form_wrapper; this.body_header = $a(this.main, 'div'); this.body = $a(this.main, 'div'); this.footer = $a(this.main, 'div'); if(this.heading) { this.page_head = new PageHeader(this.head, this); } // only tray this.meta.section_style='Simple'; // always simple! // layout this.layout = new wn.ui.form.Layout({ parent: this.body, doctype: this.doctype, frm: this, }) // state this.states = new wn.ui.form.States({ frm: this }); // footer this.setup_footer(); } _f.Frm.prototype.setup_header = function() { // header - no headers for tables and guests if(!(this.meta.istable || (this.meta.in_dialog && !this.in_form))) this.frm_head = new _f.FrmHeader(this.head, this); this.toolbar = new wn.ui.form.Toolbar({ frm: this, appframe: this.appframe }) } _f.Frm.prototype.setup_print = function() { this.print_formats = wn.meta.get_print_formats(this.meta.name); this.print_sel = $a(null, 'select', '', {width:'160px'}); add_sel_options(this.print_sel, this.print_formats); this.print_sel.value = this.print_formats[0]; } _f.Frm.prototype.print_doc = function() { if(this.doc.docstatus==2) { msgprint("Cannot Print Cancelled Documents."); return; } _p.show_dialog(); // multiple options } // email the form _f.Frm.prototype.email_doc = function(message) { new wn.views.CommunicationComposer({ doc: this.doc, subject: wn._(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 }); } // email the form _f.Frm.prototype.rename_doc = function() { wn.model.rename_doc(this.doctype, this.docname); } // notify this form of renamed records _f.Frm.prototype.rename_notify = function(dt, old, name) { // from form if(this.meta.istable) return; if(this.docname == old) this.docname = name; else return; // view_is_edit this.last_view_is_edit[name] = this.last_view_is_edit[old]; delete this.last_view_is_edit[old]; // cleanup if(this && this.opendocs[old]) { // delete docfield copy wn.meta.docfield_copy[dt][name] = wn.meta.docfield_copy[dt][old]; delete wn.meta.docfield_copy[dt][old]; } delete this.opendocs[old]; this.opendocs[name] = true; if(this.meta.in_dialog || !this.in_form) { return; } wn.re_route[window.location.hash] = '#Form/' + encodeURIComponent(this.doctype) + '/' + encodeURIComponent(name); wn.set_route('Form', this.doctype, name); } // SETUP _f.Frm.prototype.setup_meta = function(doctype) { this.meta = wn.model.get_doc('DocType',this.doctype); this.perm = wn.perm.get_perm(this.doctype); // for create if(this.meta.istable) { this.meta.in_dialog = 1 } this.setup_print(); } _f.Frm.prototype.setup_footer = function() { var me = this; // footer toolbar var f = this.footer; // save buttom f.save_area = $a(this.footer,'div','',{display:'none', marginTop:'11px'}); f.help_area = $a(this.footer,'div'); var b = $("") .click(function() { me.save("Save", null, me); }).appendTo(f.save_area); // show / hide save f.show_save = function() { $ds(me.footer.save_area); } f.hide_save = function() { $dh(me.footer.save_area); } } _f.Frm.prototype.set_intro = function(txt) { wn.utils.set_intro(this, this.body, txt); } _f.Frm.prototype.set_footnote = function(txt) { wn.utils.set_footnote(this, this.body, txt); } _f.Frm.prototype.add_custom_button = function(label, fn, icon) { this.appframe.add_button(label, fn, icon, true); } _f.Frm.prototype.clear_custom_buttons = function() { this.toolbar.refresh() } _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.setup_client_script = function() { // setup client obj if(this.meta.client_script_core || this.meta.client_script || this.meta.__js) { this.runclientscript('setup', this.doctype, this.docname); } } _f.Frm.prototype.refresh_print_layout = function() { $ds(this.print_wrapper); $dh(this.form_wrapper); var me = this; var print_callback = function(print_html) { me.print_body.innerHTML = print_html; } // print head if(cur_frm.doc.select_print_heading) cur_frm.set_print_heading(cur_frm.doc.select_print_heading) if(user!='Guest') { $di(this.view_btn_wrapper); // archive if(cur_frm.doc.__archived) { $dh(this.view_btn_wrapper); } } else { $dh(this.view_btn_wrapper); $dh(this.print_close_btn); } // create print format here _p.build(this.$print_view_select.val(), print_callback, null, 1); } _f.Frm.prototype.show_the_frm = function() { // show the dialog if(this.meta.in_dialog && !this.parent.dialog.display) { if(!this.meta.istable) this.parent.table_form = false; this.parent.dialog.show(); } } _f.Frm.prototype.set_print_heading = function(txt) { this.pformat[cur_frm.docname] = txt; } _f.Frm.prototype.defocus_rest = function() { // deselect others if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect(); } _f.Frm.prototype.refresh_header = function() { // set title // main title if(!this.meta.in_dialog || this.in_form) { set_title(this.meta.issingle ? this.doctype : this.docname); } if(wn.ui.toolbar.recent) wn.ui.toolbar.recent.add(this.doctype, this.docname, 1); // show / hide buttons if(this.frm_head) { this.frm_head.refresh(); this.toolbar.refresh(); } } _f.Frm.prototype.check_doc_perm = function() { // get perm var dt = this.parent_doctype?this.parent_doctype : this.doctype; var dn = this.parent_docname?this.parent_docname : this.docname; this.perm = wn.perm.get_perm(dt, dn); if(!this.perm[0][READ]) { wn.set_route("403"); return 0; } return 1 } _f.Frm.prototype.refresh = function(docname) { // record switch if(docname) { if(this.docname != docname && (!this.meta.in_dialog || this.in_form) && !this.meta.istable) scroll(0, 0); this.docname = docname; } if(!this.meta.istable) { cur_frm = this; this.parent.cur_frm = this; } if(this.docname) { // document to show // check permissions if(!this.check_doc_perm()) return; // read only (workflow) this.read_only = wn.workflow.is_read_only(this.doctype, this.docname); // set the doc this.doc = wn.model.get_doc(this.doctype, this.docname); // check if doctype is already open if (!this.opendocs[this.docname]) { this.check_doctype_conflict(this.docname); } else { if(this.doc && this.doc.__last_sync_on && (new Date() - this.doc.__last_sync_on) > (this.refresh_if_stale_for * 1000)) { this.reload_doc(); return; } } // do setup if(!this.setup_done) this.setup(); // set customized permissions for this record this.runclientscript('set_perm', this.doctype, this.docname); // load the record for the first time, if not loaded (call 'onload') cur_frm.cscript.is_onload = false; if(!this.opendocs[this.docname]) { cur_frm.cscript.is_onload = true; this.setnewdoc(this.docname); } // view_is_edit if(this.doc.__islocal) this.last_view_is_edit[this.docname] = 1; // new is view_is_edit this.view_is_edit = this.last_view_is_edit[this.docname]; if(this.view_is_edit || (!this.view_is_edit && this.meta.istable)) { if(this.print_wrapper) { $dh(this.print_wrapper); $ds(this.form_wrapper); } // header if(!this.meta.istable) { this.refresh_header(); } // call trigger this.runclientscript('refresh'); // trigger global trigger // to use this $(document).trigger('form_refresh'); // fields this.refresh_fields(); // dependent fields this.refresh_dependency(); // footer this.refresh_footer(); // call onload post render for callbacks to be fired if(this.cscript.is_onload) { this.runclientscript('onload_post_render', this.doctype, this.docname); } // focus on first input if(this.doc.docstatus==0) { var first = $(this.form_wrapper).find('.form-layout-row :input:first'); if(!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) { first.focus(); } } } else { this.refresh_header(); if(this.print_wrapper) { this.refresh_print_layout(); } this.runclientscript('edit_status_changed'); } $(cur_frm.wrapper).trigger('render_complete'); } } _f.Frm.prototype.refresh_footer = function() { var f = this.footer; if(f.save_area) { // if save button is there in the header if(this.frm_head && this.appframe.toolbar && this.appframe.buttons.Save && !this.save_disabled && (this.fields && this.fields.length > 7)) { f.show_save(); } else { f.hide_save(); } } } _f.Frm.prototype.refresh_field = function(fname) { cur_frm.fields_dict[fname] && cur_frm.fields_dict[fname].refresh && cur_frm.fields_dict[fname].refresh(); } _f.Frm.prototype.refresh_fields = function() { this.layout.refresh(); // cleanup activities after refresh 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); cur_frm.toggle_display(fn, false); } if(me.meta.autoname=="naming_series:" && !me.doc.__islocal) { cur_frm.toggle_display("naming_series", false); } } // Resolve "depends_on" and show / hide accordingly _f.Frm.prototype.refresh_dependency = function() { var me = this; var doc = locals[this.doctype][this.docname]; // build dependants' dictionary var has_dep = false; for(fkey in me.fields) { var f = me.fields[fkey]; f.dependencies_clear = true; if(f.df.depends_on) { has_dep = true; } } if(!has_dep)return; // show / hide based on values for(var i=me.fields.length-1;i>=0;i--) { var f = me.fields[i]; f.guardian_has_value = true; if(f.df.depends_on) { // evaluate guardian var v = doc[f.df.depends_on]; if(f.df.depends_on.substr(0,5)=='eval:') { f.guardian_has_value = eval(f.df.depends_on.substr(5)); } else if(f.df.depends_on.substr(0,3)=='fn:') { f.guardian_has_value = me.runclientscript(f.df.depends_on.substr(3), me.doctype, me.docname); } else { if(!v) { f.guardian_has_value = false; } } // show / hide if(f.guardian_has_value) { f.df.hidden = 0; f.refresh(); } else { f.df.hidden = 1; f.refresh(); } } } } // setnewdoc is called when a record is loaded for the first time // ====================================================================================== _f.Frm.prototype.setnewdoc = function(docname) { // moved this call to refresh function // this.check_doctype_conflict(docname); // if loaded if(this.opendocs[docname]) { // already exists this.docname=docname; return; } // make a copy of the doctype for client script settings // each record will have its own client script wn.meta.make_docfield_copy_for(this.doctype,docname); this.docname = docname; var me = this; var viewname = this.meta.issingle ? this.doctype : docname; // Client Script this.runclientscript('onload', this.doctype, this.docname); this.last_view_is_edit[docname] = 1; if(cint(this.meta.read_only_onload)) this.last_view_is_edit[docname] = 0; this.opendocs[docname] = true; } _f.Frm.prototype.edit_doc = function() { // set fields this.last_view_is_edit[this.docname] = true; this.refresh(); } _f.Frm.prototype.show_doc = function(dn) { this.refresh(dn); } _f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) { var me = this; if(this.docname) { // make doc list var doclist = wn.model.compress(make_doclist(this.doctype, this.docname)); // send to run if(callingfield) $(callingfield.input).set_working(); $c('runserverobj', {'docs':doclist, 'method':scriptname }, function(r, rtxt) { // run refresh if(onrefresh) onrefresh(r,rtxt); // fields me.refresh_fields(); // dependent fields me.refresh_dependency(); // enable button if(callingfield) $(callingfield.input).done_working(); } ); } } _f.Frm.prototype.runclientscript = function(caller, cdt, cdn) { if(!cdt)cdt = this.doctype; if(!cdn)cdn = this.docname; var ret = null; var doc = locals[cur_frm.doc.doctype][cur_frm.doc.name]; try { if(this.cscript[caller]) ret = this.cscript[caller](doc, cdt, cdn); if(this.cscript['custom_'+caller]) ret += this.cscript['custom_'+caller](doc, cdt, cdn); } catch(e) { validated = false; // show error message this.log_error(caller, e); } if(caller && caller.toLowerCase()=='setup') { this.setup_client_js(); } return ret; } _f.Frm.prototype.setup_client_js = function(caller, cdt, cdn) { var doctype = wn.model.get_doc('DocType', this.doctype); // js var cs = doctype.__js || (doctype.client_script_core + doctype.client_script); if(cs) { try { var tmp = eval(cs); } catch(e) { show_alert("Error in Client Script."); this.log_error(caller || "setup_client_js", e); } } // css if(doctype.__css) wn.dom.set_style(doctype.__css); // ---Client String---- if(doctype.client_string) { // split client string this.cstring = {}; var elist = doctype.client_string.split('---'); for(var i=1;i