You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13 年之前
13 年之前
13 年之前
12 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
12 年之前
12 年之前
13 年之前
13 年之前
12 年之前
12 年之前
12 年之前
12 年之前
12 年之前
13 年之前
12 年之前
12 年之前
12 年之前
12 年之前
13 年之前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. // Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. //
  3. // MIT License (MIT)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a
  6. // copy of this software and associated documentation files (the "Software"),
  7. // to deal in the Software without restriction, including without limitation
  8. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. // and/or sell copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22. /* Form page structure
  23. + this.parent (either FormContainer or Dialog)
  24. + this.wrapper
  25. + this.content
  26. + wn.PageLayout (this.page_layout)
  27. + this.wrapper
  28. + this.wtab (table)
  29. + this.main
  30. + this.head
  31. + this.body
  32. + this.layout
  33. + this.footer
  34. + this.sidebar
  35. + this.print_wrapper
  36. + this.head
  37. */
  38. wn.provide('_f');
  39. wn.provide('wn.ui.form');
  40. wn.ui.form.Controller = Class.extend({
  41. init: function(opts) {
  42. $.extend(this, opts);
  43. }
  44. });
  45. _f.frms = {};
  46. _f.Frm = function(doctype, parent, in_form) {
  47. this.docname = '';
  48. this.doctype = doctype;
  49. this.display = 0;
  50. this.refresh_if_stale_for = 120;
  51. var me = this;
  52. this.last_view_is_edit = {};
  53. this.opendocs = {};
  54. this.sections = [];
  55. this.grids = [];
  56. this.cscript = new wn.ui.form.Controller({frm:this});
  57. this.pformat = {};
  58. this.fetch_dict = {};
  59. this.parent = parent;
  60. this.tinymce_id_list = [];
  61. this.setup_meta(doctype);
  62. // show in form instead of in dialog, when called using url (router.js)
  63. this.in_form = in_form ? true : false;
  64. // notify on rename
  65. var me = this;
  66. $(document).bind('rename', function(event, dt, old_name, new_name) {
  67. if(dt==me.doctype)
  68. me.rename_notify(dt, old_name, new_name)
  69. });
  70. }
  71. _f.Frm.prototype.check_doctype_conflict = function(docname) {
  72. var me = this;
  73. if(this.doctype=='DocType' && docname=='DocType') {
  74. msgprint('Allowing DocType, DocType. Be careful!')
  75. } else if(this.doctype=='DocType') {
  76. if (wn.views.formview[docname] || wn.pages['List/'+docname]) {
  77. msgprint("Cannot open DocType when its instance is open")
  78. throw 'doctype open conflict'
  79. }
  80. } else {
  81. if (wn.views.formview.DocType && wn.views.formview.DocType.frm.opendocs[this.doctype]) {
  82. msgprint("Cannot open instance when its DocType is open")
  83. throw 'doctype open conflict'
  84. }
  85. }
  86. }
  87. _f.Frm.prototype.setup = function() {
  88. var me = this;
  89. this.fields = [];
  90. this.fields_dict = {};
  91. this.state_fieldname = wn.workflow.get_state_fieldname(this.doctype);
  92. // wrapper
  93. this.wrapper = this.parent;
  94. // create area for print fomrat
  95. this.setup_print_layout();
  96. // 2 column layout
  97. this.setup_std_layout();
  98. // client script must be called after "setup" - there are no fields_dict attached to the frm otherwise
  99. this.setup_client_script();
  100. this.setup_header();
  101. this.setup_done = true;
  102. }
  103. _f.Frm.prototype.setup_print_layout = function() {
  104. var me = this;
  105. this.print_wrapper = $a(this.wrapper, 'div');
  106. wn.ui.make_app_page({
  107. parent: this.print_wrapper,
  108. single_column: true,
  109. set_document_title: false,
  110. title: me.doctype + ": Print View",
  111. module: me.meta.module
  112. });
  113. var appframe = this.print_wrapper.appframe;
  114. appframe.add_button(wn._("View Details"), function() {
  115. me.edit_doc();
  116. }).addClass("btn-success");
  117. appframe.add_button(wn._("Print"), function() {
  118. me.print_doc();
  119. }, 'icon-print');
  120. this.$print_view_select = appframe.add_select(wn._("Select Preview"), this.print_formats)
  121. .css({"float":"right"})
  122. .val(this.print_formats[0])
  123. .change(function() {
  124. me.refresh_print_layout();
  125. })
  126. appframe.add_ripped_paper_effect(this.print_wrapper);
  127. var layout_main = $(this.print_wrapper).find(".layout-main");
  128. this.print_body = $("<div style='margin: 25px'>").appendTo(layout_main)
  129. .css("min-height", "400px").get(0);
  130. }
  131. _f.Frm.prototype.onhide = function() {
  132. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  133. }
  134. _f.Frm.prototype.setup_std_layout = function() {
  135. this.page_layout = new wn.PageLayout({
  136. parent: this.wrapper,
  137. main_width: (this.meta.in_dialog && !this.in_form) ? '100%' : '75%',
  138. sidebar_width: (this.meta.in_dialog && !this.in_form) ? '0%' : '25%'
  139. })
  140. // only tray
  141. this.meta.section_style='Simple'; // always simple!
  142. // layout
  143. this.layout = new Layout(this.page_layout.body, '100%');
  144. // sidebar
  145. if(this.meta.in_dialog && !this.in_form) {
  146. // hide sidebar
  147. $(this.page_layout.wrapper).removeClass('layout-wrapper-background');
  148. $(this.page_layout.main).removeClass('layout-main-section');
  149. $(this.page_layout.sidebar_area).toggle(false);
  150. } else {
  151. // module link
  152. this.setup_sidebar();
  153. }
  154. // state
  155. this.states = new wn.ui.form.States({
  156. frm: this
  157. });
  158. // watermark
  159. if(!this.meta.issingle) {
  160. $('<div style="font-size: 21px; color: #aaa; float: right;\
  161. margin-top: -5px; margin-right: -5px; z-index: 5;">'
  162. + wn._(this.doctype) + '</div>')
  163. .prependTo(this.page_layout.main);
  164. }
  165. // footer
  166. this.setup_footer();
  167. // create fields
  168. this.setup_fields_std();
  169. }
  170. _f.Frm.prototype.setup_header = function() {
  171. // header - no headers for tables and guests
  172. if(!(this.meta.istable || (this.meta.in_dialog && !this.in_form)))
  173. this.frm_head = new _f.FrmHeader(this.page_layout.head, this);
  174. }
  175. _f.Frm.prototype.setup_print = function() {
  176. this.print_formats = wn.meta.get_print_formats(this.meta.name);
  177. this.print_sel = $a(null, 'select', '', {width:'160px'});
  178. add_sel_options(this.print_sel, this.print_formats);
  179. this.print_sel.value = this.print_formats[0];
  180. }
  181. _f.Frm.prototype.print_doc = function() {
  182. if(this.doc.docstatus==2) {
  183. msgprint("Cannot Print Cancelled Documents.");
  184. return;
  185. }
  186. _p.show_dialog(); // multiple options
  187. }
  188. // email the form
  189. _f.Frm.prototype.email_doc = function(message) {
  190. new wn.views.CommunicationComposer({
  191. doc: this.doc,
  192. subject: wn._(this.meta.name) + ': ' + this.docname,
  193. recipients: this.doc.email || this.doc.email_id || this.doc.contact_email,
  194. attach_document_print: true,
  195. message: message,
  196. real_name: this.doc.real_name || this.doc.contact_display || this.doc.contact_name
  197. });
  198. }
  199. // email the form
  200. _f.Frm.prototype.rename_doc = function() {
  201. wn.model.rename_doc(this.doctype, this.docname);
  202. }
  203. // notify this form of renamed records
  204. _f.Frm.prototype.rename_notify = function(dt, old, name) {
  205. // from form
  206. if(this.meta.istable)
  207. return;
  208. if(this.docname == old)
  209. this.docname = name;
  210. else
  211. return;
  212. // view_is_edit
  213. this.last_view_is_edit[name] = this.last_view_is_edit[old];
  214. delete this.last_view_is_edit[old];
  215. // cleanup
  216. if(this && this.opendocs[old]) {
  217. // delete docfield copy
  218. wn.meta.docfield_copy[dt][name] = wn.meta.docfield_copy[dt][old];
  219. delete wn.meta.docfield_copy[dt][old];
  220. }
  221. delete this.opendocs[old];
  222. this.opendocs[name] = true;
  223. if(this.meta.in_dialog || !this.in_form) {
  224. return;
  225. }
  226. wn.re_route[window.location.hash] = '#Form/' + encodeURIComponent(this.doctype) + '/' + encodeURIComponent(name);
  227. wn.set_route('Form', this.doctype, name);
  228. }
  229. // SETUP
  230. _f.Frm.prototype.setup_meta = function(doctype) {
  231. this.meta = wn.model.get_doc('DocType',this.doctype);
  232. this.perm = wn.perm.get_perm(this.doctype); // for create
  233. if(this.meta.istable) { this.meta.in_dialog = 1 }
  234. this.setup_print();
  235. }
  236. _f.Frm.prototype.setup_sidebar = function() {
  237. this.sidebar = new wn.widgets.form.sidebar.Sidebar(this);
  238. }
  239. _f.Frm.prototype.setup_footer = function() {
  240. var me = this;
  241. // footer toolbar
  242. var f = this.page_layout.footer;
  243. // save buttom
  244. f.save_area = $a(this.page_layout.footer,'div','',{display:'none', marginTop:'11px'});
  245. f.help_area = $a(this.page_layout.footer,'div');
  246. var b = $("<button class='btn btn-info'><i class='icon-save'></i> Save</button>")
  247. .click(function() { me.save("Save", null, me); }).appendTo(f.save_area);
  248. // show / hide save
  249. f.show_save = function() {
  250. $ds(me.page_layout.footer.save_area);
  251. }
  252. f.hide_save = function() {
  253. $dh(me.page_layout.footer.save_area);
  254. }
  255. }
  256. _f.Frm.prototype.set_intro = function(txt) {
  257. wn.utils.set_intro(this, this.page_layout.body, txt);
  258. }
  259. _f.Frm.prototype.set_footnote = function(txt) {
  260. wn.utils.set_footnote(this, this.page_layout.body, txt);
  261. }
  262. _f.Frm.prototype.setup_fields_std = function() {
  263. var fl = wn.meta.docfield_list[this.doctype];
  264. fl.sort(function(a,b) { return a.idx - b.idx});
  265. if(fl[0]&&fl[0].fieldtype!="Section Break" || get_url_arg('embed')) {
  266. this.layout.addrow(); // default section break
  267. if(fl[0].fieldtype!="Column Break") {// without column too
  268. var c = this.layout.addcell();
  269. $y(c.wrapper, {padding: '8px'});
  270. }
  271. }
  272. var sec;
  273. for(var i=0;i<fl.length;i++) {
  274. var f=fl[i];
  275. // if section break and next item
  276. // is a section break then ignore
  277. if(f.fieldtype=='Section Break' && fl[i+1] && fl[i+1].fieldtype=='Section Break')
  278. continue;
  279. var fn = f.fieldname?f.fieldname:f.label;
  280. var fld = make_field(f, this.doctype, this.layout.cur_cell, this);
  281. this.fields[this.fields.length] = fld;
  282. this.fields_dict[fn] = fld;
  283. if(sec && ['Section Break', 'Column Break'].indexOf(f.fieldtype)==-1) {
  284. fld.parent_section = sec;
  285. sec.fields.push(fld);
  286. }
  287. if(f.fieldtype=='Section Break') {
  288. sec = fld;
  289. this.sections.push(fld);
  290. }
  291. // default col-break after sec-break
  292. if((f.fieldtype=='Section Break')&&(fl[i+1])&&(fl[i+1].fieldtype!='Column Break')) {
  293. var c = this.layout.addcell();
  294. $y(c.wrapper, {padding: '8px'});
  295. }
  296. }
  297. }
  298. _f.Frm.prototype.add_custom_button = function(label, fn, icon) {
  299. this.frm_head.appframe.add_button(label, fn, icon);
  300. }
  301. _f.Frm.prototype.clear_custom_buttons = function() {
  302. this.frm_head.refresh_toolbar()
  303. }
  304. _f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) {
  305. if(!this.fetch_dict[link_field]) {
  306. this.fetch_dict[link_field] = {'columns':[], 'fields':[]}
  307. }
  308. this.fetch_dict[link_field].columns.push(src_field);
  309. this.fetch_dict[link_field].fields.push(tar_field);
  310. }
  311. _f.Frm.prototype.setup_client_script = function() {
  312. // setup client obj
  313. if(this.meta.client_script_core || this.meta.client_script || this.meta.__js) {
  314. this.runclientscript('setup', this.doctype, this.docname);
  315. }
  316. }
  317. _f.Frm.prototype.refresh_print_layout = function() {
  318. $ds(this.print_wrapper);
  319. $dh(this.page_layout.wrapper);
  320. var me = this;
  321. var print_callback = function(print_html) {
  322. me.print_body.innerHTML = print_html;
  323. }
  324. // print head
  325. if(cur_frm.doc.select_print_heading)
  326. cur_frm.set_print_heading(cur_frm.doc.select_print_heading)
  327. if(user!='Guest') {
  328. $di(this.view_btn_wrapper);
  329. // archive
  330. if(cur_frm.doc.__archived) {
  331. $dh(this.view_btn_wrapper);
  332. }
  333. } else {
  334. $dh(this.view_btn_wrapper);
  335. $dh(this.print_close_btn);
  336. }
  337. // create print format here
  338. _p.build(this.$print_view_select.val(), print_callback, null, 1);
  339. }
  340. _f.Frm.prototype.show_the_frm = function() {
  341. // show the dialog
  342. if(this.meta.in_dialog && !this.parent.dialog.display) {
  343. if(!this.meta.istable)
  344. this.parent.table_form = false;
  345. this.parent.dialog.show();
  346. }
  347. }
  348. _f.Frm.prototype.set_print_heading = function(txt) {
  349. this.pformat[cur_frm.docname] = txt;
  350. }
  351. _f.Frm.prototype.defocus_rest = function() {
  352. // deselect others
  353. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  354. }
  355. _f.Frm.prototype.refresh_header = function() {
  356. // set title
  357. // main title
  358. if(!this.meta.in_dialog || this.in_form) {
  359. set_title(this.meta.issingle ? this.doctype : this.docname);
  360. }
  361. if(wn.ui.toolbar.recent)
  362. wn.ui.toolbar.recent.add(this.doctype, this.docname, 1);
  363. // show / hide buttons
  364. if(this.frm_head)this.frm_head.refresh();
  365. }
  366. _f.Frm.prototype.check_doc_perm = function() {
  367. // get perm
  368. var dt = this.parent_doctype?this.parent_doctype : this.doctype;
  369. var dn = this.parent_docname?this.parent_docname : this.docname;
  370. this.perm = wn.perm.get_perm(dt, dn);
  371. if(!this.perm[0][READ]) {
  372. wn.set_route("403");
  373. return 0;
  374. }
  375. return 1
  376. }
  377. _f.Frm.prototype.refresh = function(docname) {
  378. // record switch
  379. if(docname) {
  380. if(this.docname != docname && (!this.meta.in_dialog || this.in_form) &&
  381. !this.meta.istable)
  382. scroll(0, 0);
  383. this.docname = docname;
  384. }
  385. if(!this.meta.istable) {
  386. cur_frm = this;
  387. this.parent.cur_frm = this;
  388. }
  389. if(this.docname) { // document to show
  390. // check permissions
  391. if(!this.check_doc_perm()) return;
  392. // read only (workflow)
  393. this.read_only = wn.workflow.is_read_only(this.doctype, this.docname);
  394. // set the doc
  395. this.doc = wn.model.get_doc(this.doctype, this.docname);
  396. // check if doctype is already open
  397. if (!this.opendocs[this.docname]) {
  398. this.check_doctype_conflict(this.docname);
  399. } else {
  400. if(this.doc && this.doc.__last_sync_on &&
  401. (new Date() - this.doc.__last_sync_on) > (this.refresh_if_stale_for * 1000)) {
  402. this.reload_doc();
  403. return;
  404. }
  405. }
  406. // do setup
  407. if(!this.setup_done) this.setup();
  408. // set customized permissions for this record
  409. this.runclientscript('set_perm',this.doctype, this.docname);
  410. // load the record for the first time, if not loaded (call 'onload')
  411. cur_frm.cscript.is_onload = false;
  412. if(!this.opendocs[this.docname]) {
  413. cur_frm.cscript.is_onload = true;
  414. this.setnewdoc(this.docname);
  415. }
  416. // view_is_edit
  417. if(this.doc.__islocal)
  418. this.last_view_is_edit[this.docname] = 1; // new is view_is_edit
  419. this.view_is_edit = this.last_view_is_edit[this.docname];
  420. if(this.view_is_edit || (!this.view_is_edit && this.meta.istable)) {
  421. if(this.print_wrapper) {
  422. $dh(this.print_wrapper);
  423. $ds(this.page_layout.wrapper);
  424. }
  425. // header
  426. if(!this.meta.istable) {
  427. this.refresh_header();
  428. this.sidebar && this.sidebar.refresh();
  429. }
  430. // call trigger
  431. this.runclientscript('refresh');
  432. // trigger global trigger
  433. // to use this
  434. $(document).trigger('form_refresh');
  435. // fields
  436. this.refresh_fields();
  437. // dependent fields
  438. this.refresh_dependency();
  439. // footer
  440. this.refresh_footer();
  441. // layout
  442. if(this.layout) this.layout.show();
  443. // call onload post render for callbacks to be fired
  444. if(this.cscript.is_onload) {
  445. this.runclientscript('onload_post_render', this.doctype, this.docname);
  446. }
  447. // focus on first input
  448. if(this.doc.docstatus==0) {
  449. var first = $(this.wrapper).find('.form-layout-row :input:first');
  450. if(!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
  451. first.focus();
  452. }
  453. }
  454. } else {
  455. this.refresh_header();
  456. if(this.print_wrapper) {
  457. this.refresh_print_layout();
  458. }
  459. this.runclientscript('edit_status_changed');
  460. }
  461. $(cur_frm.wrapper).trigger('render_complete');
  462. }
  463. }
  464. _f.Frm.prototype.refresh_footer = function() {
  465. var f = this.page_layout.footer;
  466. if(f.save_area) {
  467. // if save button is there in the header
  468. if(this.frm_head && this.frm_head.appframe.toolbar
  469. && this.frm_head.appframe.toolbar.find(".btn-save").length && !this.save_disabled
  470. && (this.fields && this.fields.length > 7)) {
  471. f.show_save();
  472. } else {
  473. f.hide_save();
  474. }
  475. }
  476. }
  477. _f.Frm.prototype.refresh_field = function(fname) {
  478. cur_frm.fields_dict[fname] && cur_frm.fields_dict[fname].refresh
  479. && cur_frm.fields_dict[fname].refresh();
  480. }
  481. _f.Frm.prototype.refresh_fields = function() {
  482. // refresh fields
  483. for(var i=0; i<this.fields.length; i++) {
  484. var f = this.fields[i];
  485. f.perm = this.perm;
  486. f.docname = this.docname;
  487. // if field is identifiable (not blank section or column break)
  488. // get the "customizable" parameters for this record
  489. var fn = f.df.fieldname || f.df.label;
  490. if(fn)
  491. f.df = wn.meta.get_docfield(this.doctype, fn, this.docname);
  492. if(f.df.fieldtype!='Section Break' && f.refresh) {
  493. f.refresh();
  494. }
  495. }
  496. // refresh sections
  497. $.each(this.sections, function(i, f) {
  498. f.refresh(true);
  499. })
  500. // cleanup activities after refresh
  501. this.cleanup_refresh(this);
  502. }
  503. _f.Frm.prototype.cleanup_refresh = function() {
  504. var me = this;
  505. if(me.fields_dict['amended_from']) {
  506. if (me.doc.amended_from) {
  507. unhide_field('amended_from');
  508. if (me.fields_dict['amendment_date']) unhide_field('amendment_date');
  509. } else {
  510. hide_field('amended_from');
  511. if (me.fields_dict['amendment_date']) hide_field('amendment_date');
  512. }
  513. }
  514. if(me.fields_dict['trash_reason']) {
  515. if(me.doc.trash_reason && me.doc.docstatus == 2) {
  516. unhide_field('trash_reason');
  517. } else {
  518. hide_field('trash_reason');
  519. }
  520. }
  521. if(me.meta.autoname && me.meta.autoname.substr(0,6)=='field:' && !me.doc.__islocal) {
  522. var fn = me.meta.autoname.substr(6);
  523. cur_frm.toggle_display(fn, false);
  524. }
  525. if(me.meta.autoname=="naming_series:" && !me.doc.__islocal) {
  526. cur_frm.toggle_display("naming_series", false);
  527. }
  528. }
  529. // Resolve "depends_on" and show / hide accordingly
  530. _f.Frm.prototype.refresh_dependency = function() {
  531. var me = this;
  532. var doc = locals[this.doctype][this.docname];
  533. // build dependants' dictionary
  534. var has_dep = false;
  535. for(fkey in me.fields) {
  536. var f = me.fields[fkey];
  537. f.dependencies_clear = true;
  538. if(f.df.depends_on) {
  539. has_dep = true;
  540. }
  541. }
  542. if(!has_dep)return;
  543. // show / hide based on values
  544. for(var i=me.fields.length-1;i>=0;i--) {
  545. var f = me.fields[i];
  546. f.guardian_has_value = true;
  547. if(f.df.depends_on) {
  548. // evaluate guardian
  549. var v = doc[f.df.depends_on];
  550. if(f.df.depends_on.substr(0,5)=='eval:') {
  551. f.guardian_has_value = eval(f.df.depends_on.substr(5));
  552. } else if(f.df.depends_on.substr(0,3)=='fn:') {
  553. f.guardian_has_value = me.runclientscript(f.df.depends_on.substr(3), me.doctype, me.docname);
  554. } else {
  555. if(!v) {
  556. f.guardian_has_value = false;
  557. }
  558. }
  559. // show / hide
  560. if(f.guardian_has_value) {
  561. f.df.hidden = 0;
  562. f.refresh();
  563. } else {
  564. f.df.hidden = 1;
  565. f.refresh();
  566. }
  567. }
  568. }
  569. }
  570. // setnewdoc is called when a record is loaded for the first time
  571. // ======================================================================================
  572. _f.Frm.prototype.setnewdoc = function(docname) {
  573. // moved this call to refresh function
  574. // this.check_doctype_conflict(docname);
  575. // if loaded
  576. if(this.opendocs[docname]) { // already exists
  577. this.docname=docname;
  578. return;
  579. }
  580. // make a copy of the doctype for client script settings
  581. // each record will have its own client script
  582. wn.meta.make_docfield_copy_for(this.doctype,docname);
  583. this.docname = docname;
  584. var me = this;
  585. var viewname = this.meta.issingle ? this.doctype : docname;
  586. // Client Script
  587. this.runclientscript('onload', this.doctype, this.docname);
  588. this.last_view_is_edit[docname] = 1;
  589. if(cint(this.meta.read_only_onload)) this.last_view_is_edit[docname] = 0;
  590. this.opendocs[docname] = true;
  591. }
  592. _f.Frm.prototype.edit_doc = function() {
  593. // set fields
  594. this.last_view_is_edit[this.docname] = true;
  595. this.refresh();
  596. }
  597. _f.Frm.prototype.show_doc = function(dn) {
  598. this.refresh(dn);
  599. }
  600. _f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) {
  601. var me = this;
  602. if(this.docname) {
  603. // make doc list
  604. var doclist = wn.model.compress(make_doclist(this.doctype, this.docname));
  605. // send to run
  606. if(callingfield)
  607. $(callingfield.input).set_working();
  608. $c('runserverobj', {'docs':doclist, 'method':scriptname },
  609. function(r, rtxt) {
  610. // run refresh
  611. if(onrefresh)
  612. onrefresh(r,rtxt);
  613. // fields
  614. me.refresh_fields();
  615. // dependent fields
  616. me.refresh_dependency();
  617. // enable button
  618. if(callingfield)
  619. $(callingfield.input).done_working();
  620. }
  621. );
  622. }
  623. }
  624. _f.Frm.prototype.runclientscript = function(caller, cdt, cdn) {
  625. if(!cdt)cdt = this.doctype;
  626. if(!cdn)cdn = this.docname;
  627. var ret = null;
  628. var doc = locals[cur_frm.doc.doctype][cur_frm.doc.name];
  629. try {
  630. if(this.cscript[caller])
  631. ret = this.cscript[caller](doc, cdt, cdn);
  632. if(this.cscript['custom_'+caller])
  633. ret += this.cscript['custom_'+caller](doc, cdt, cdn);
  634. } catch(e) {
  635. validated = false;
  636. console.log(e);
  637. }
  638. if(caller && caller.toLowerCase()=='setup') {
  639. this.setup_client_js();
  640. }
  641. return ret;
  642. }
  643. _f.Frm.prototype.setup_client_js = function(caller, cdt, cdn) {
  644. var doctype = wn.model.get_doc('DocType', this.doctype);
  645. // js
  646. var cs = doctype.__js || (doctype.client_script_core + doctype.client_script);
  647. if(cs) {
  648. try {
  649. var tmp = eval(cs);
  650. } catch(e) {
  651. show_alert("Error in Client Script.")
  652. console.log(e);
  653. }
  654. }
  655. // css
  656. if(doctype.__css) set_style(doctype.__css)
  657. // ---Client String----
  658. if(doctype.client_string) { // split client string
  659. this.cstring = {};
  660. var elist = doctype.client_string.split('---');
  661. for(var i=1;i<elist.length;i=i+2) {
  662. this.cstring[strip(elist[i])] = elist[i+1];
  663. }
  664. }
  665. }
  666. _f.Frm.prototype.copy_doc = function(onload, from_amend) {
  667. if(!this.perm[0][CREATE]) {
  668. msgprint('You are not allowed to create '+this.meta.name);
  669. return;
  670. }
  671. var dn = this.docname;
  672. // copy parent
  673. var newdoc = wn.model.copy_doc(this.doctype, dn, from_amend);
  674. // do not copy attachments
  675. if(this.meta.allow_attach && newdoc.file_list && !from_amend)
  676. newdoc.file_list = null;
  677. // copy chidren
  678. var dl = make_doclist(this.doctype, dn);
  679. // table fields dict - for no_copy check
  680. var tf_dict = {};
  681. for(var d in dl) {
  682. d1 = dl[d];
  683. // get tabel field
  684. if(d1.parentfield && !tf_dict[d1.parentfield]) {
  685. tf_dict[d1.parentfield] = wn.meta.get_docfield(d1.parenttype, d1.parentfield);
  686. }
  687. if(d1.parent==dn && cint(tf_dict[d1.parentfield].no_copy)!=1) {
  688. var ch = wn.model.copy_doc(d1.doctype, d1.name, from_amend);
  689. ch.parent = newdoc.name;
  690. ch.docstatus = 0;
  691. ch.owner = user;
  692. ch.creation = '';
  693. ch.modified_by = user;
  694. ch.modified = '';
  695. }
  696. }
  697. newdoc.__islocal = 1;
  698. newdoc.docstatus = 0;
  699. newdoc.owner = user;
  700. newdoc.creation = '';
  701. newdoc.modified_by = user;
  702. newdoc.modified = '';
  703. if(onload)onload(newdoc);
  704. loaddoc(newdoc.doctype, newdoc.name);
  705. }
  706. _f.Frm.prototype.reload_doc = function() {
  707. this.check_doctype_conflict(this.docname);
  708. var me = this;
  709. var onsave = function(r, rtxt) {
  710. // n tweets and last comment
  711. //me.runclientscript('setup', me.doctype, me.docname);
  712. me.refresh();
  713. }
  714. if(me.doc.__islocal) {
  715. wn.call({
  716. method: "webnotes.widgets.form.load.getdoctype",
  717. args: {
  718. doctype: me.doctype
  719. },
  720. callback: function(r) {
  721. me.refresh();
  722. }
  723. })
  724. } else {
  725. wn.call({
  726. method: "webnotes.widgets.form.load.getdoc",
  727. args: {
  728. doctype: me.doctype,
  729. name: me.docname
  730. },
  731. callback: function(r) {
  732. me.refresh();
  733. }
  734. });
  735. }
  736. }
  737. var validated;
  738. _f.Frm.prototype.save = function(save_action, callback, btn, on_error) {
  739. $(document.activeElement).blur();
  740. var me = this;
  741. if((!this.meta.in_dialog || this.in_form) && !this.meta.istable)
  742. scroll(0, 0);
  743. // validate
  744. if(save_action!="Cancel") {
  745. validated = true;
  746. this.runclientscript('validate');
  747. if(!validated) {
  748. if(on_error)
  749. on_error();
  750. return;
  751. }
  752. }
  753. var doclist = new wn.model.DocList(this.doctype, this.docname);
  754. doclist.save(save_action || "Save", function(r) {
  755. if(!r.exc) {
  756. me.refresh();
  757. if(save_action==="Save") {
  758. me.runclientscript("after_save", me.doctype, me.docname);
  759. }
  760. } else {
  761. if(on_error)
  762. on_error();
  763. }
  764. callback && callback(r);
  765. }, btn);
  766. }
  767. _f.Frm.prototype.savesubmit = function(btn, on_error) {
  768. var me = this;
  769. wn.confirm("Permanently Submit "+this.docname+"?", function() {
  770. me.save('Submit', function(r) {
  771. if(!r.exc) {
  772. me.runclientscript('on_submit', me.doctype, me.docname);
  773. }
  774. }, btn, on_error);
  775. });
  776. }
  777. _f.Frm.prototype.savecancel = function(btn, on_error) {
  778. var me = this;
  779. wn.confirm("Permanently Cancel "+this.docname+"?", function() {
  780. me.runclientscript("before_cancel", me.doctype, me.docname);
  781. var doclist = new wn.model.DocList(me.doctype, me.docname);
  782. doclist.cancel(function(r) {
  783. if(!r.exc) {
  784. me.refresh();
  785. me.runclientscript("after_cancel", me.doctype, me.docname);
  786. }
  787. }, btn, on_error);
  788. });
  789. }
  790. // delete the record
  791. _f.Frm.prototype.savetrash = function() {
  792. wn.model.delete_doc(this.doctype, this.docname, function(r) {
  793. window.history.back();
  794. })
  795. }
  796. _f.Frm.prototype.amend_doc = function() {
  797. if(!this.fields_dict['amended_from']) {
  798. alert('"amended_from" field must be present to do an amendment.');
  799. return;
  800. }
  801. var me = this;
  802. var fn = function(newdoc) {
  803. newdoc.amended_from = me.docname;
  804. if(me.fields_dict && me.fields_dict['amendment_date'])
  805. newdoc.amendment_date = dateutil.obj_to_str(new Date());
  806. }
  807. this.copy_doc(fn, 1);
  808. }
  809. _f.Frm.prototype.disable_save = function() {
  810. // IMPORTANT: this function should be called in refresh event
  811. cur_frm.save_disabled = true;
  812. cur_frm.page_layout.footer.hide_save();
  813. cur_frm.frm_head.appframe.buttons.Save.remove();
  814. }
  815. _f.get_value = function(dt, dn, fn) {
  816. if(locals[dt] && locals[dt][dn])
  817. return locals[dt][dn][fn];
  818. }
  819. _f.Frm.prototype.set_value_in_locals = function(dt, dn, fn, v) {
  820. var d = locals[dt][dn];
  821. if (!d) return;
  822. var changed = d[fn] != v;
  823. if(changed && (d[fn]==null || v==null) && (cstr(d[fn])==cstr(v)))
  824. changed = false;
  825. if(changed) {
  826. d[fn] = v;
  827. if(d.parenttype)
  828. d.__unsaved = 1;
  829. this.set_unsaved();
  830. }
  831. }
  832. _f.Frm.prototype.set_unsaved = function() {
  833. if(cur_frm.doc.__unsaved)
  834. return;
  835. cur_frm.doc.__unsaved = 1;
  836. var frm_head;
  837. if(cur_frm.frm_head) {
  838. frm_head = cur_frm.frm_head;
  839. } else if(wn.container.page.frm && wn.container.page.frm.frm_head) {
  840. frm_head = wn.container.page.frm.frm_head
  841. }
  842. if(frm_head) frm_head.refresh_labels();
  843. }
  844. _f.Frm.prototype.show_comments = function() {
  845. if(!cur_frm.comments) {
  846. cur_frm.comments = new Dialog(540, 400, 'Comments');
  847. cur_frm.comments.comment_body = $a(cur_frm.comments.body, 'div', 'dialog_frm');
  848. $y(cur_frm.comments.body, {backgroundColor:'#EEE'});
  849. cur_frm.comments.list = new CommentList(cur_frm.comments.comment_body);
  850. }
  851. cur_frm.comments.list.dt = cur_frm.doctype;
  852. cur_frm.comments.list.dn = cur_frm.docname;
  853. cur_frm.comments.show();
  854. cur_frm.comments.list.run();
  855. }