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.

form.js 20 KiB

13 years ago
13 years ago
12 years ago
11 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. /* Form page structure
  4. + this.parent (either FormContainer or Dialog)
  5. + this.wrapper
  6. + this.toolbar
  7. + this.form_wrapper
  8. + this.head
  9. + this.body
  10. + this.layout
  11. + this.sidebar
  12. + this.footer
  13. */
  14. wn.provide('_f');
  15. wn.provide('wn.ui.form');
  16. wn.ui.form.Controller = Class.extend({
  17. init: function(opts) {
  18. $.extend(this, opts);
  19. this.setup && this.setup();
  20. }
  21. });
  22. _f.frms = {};
  23. _f.Frm = function(doctype, parent, in_form) {
  24. this.docname = '';
  25. this.doctype = doctype;
  26. this.display = 0;
  27. this.refresh_if_stale_for = 120;
  28. var me = this;
  29. this.opendocs = {};
  30. this.sections = [];
  31. this.grids = [];
  32. this.cscript = new wn.ui.form.Controller({frm:this});
  33. this.pformat = {};
  34. this.fetch_dict = {};
  35. this.parent = parent;
  36. this.tinymce_id_list = [];
  37. this.setup_meta(doctype);
  38. // show in form instead of in dialog, when called using url (router.js)
  39. this.in_form = in_form ? true : false;
  40. // notify on rename
  41. var me = this;
  42. $(document).on('rename', function(event, dt, old_name, new_name) {
  43. if(dt==me.doctype)
  44. me.rename_notify(dt, old_name, new_name)
  45. });
  46. }
  47. _f.Frm.prototype.check_doctype_conflict = function(docname) {
  48. var me = this;
  49. if(this.doctype=='DocType' && docname=='DocType') {
  50. msgprint('Allowing DocType, DocType. Be careful!')
  51. } else if(this.doctype=='DocType') {
  52. if (wn.views.formview[docname] || wn.pages['List/'+docname]) {
  53. msgprint("Cannot open DocType when its instance is open")
  54. throw 'doctype open conflict'
  55. }
  56. } else {
  57. if (wn.views.formview.DocType && wn.views.formview.DocType.frm.opendocs[this.doctype]) {
  58. msgprint("Cannot open instance when its DocType is open")
  59. throw 'doctype open conflict'
  60. }
  61. }
  62. }
  63. _f.Frm.prototype.setup = function() {
  64. var me = this;
  65. this.fields = [];
  66. this.fields_dict = {};
  67. this.state_fieldname = wn.workflow.get_state_fieldname(this.doctype);
  68. // wrapper
  69. this.wrapper = this.parent;
  70. wn.ui.make_app_page({
  71. parent: this.wrapper,
  72. single_column: true
  73. });
  74. this.appframe = this.wrapper.appframe;
  75. this.layout_main = $(this.wrapper)
  76. .find(".layout-main")
  77. .css({"padding-bottom": "0px"})
  78. .get(0);
  79. this.toolbar = new wn.ui.form.Toolbar({
  80. frm: this,
  81. appframe: this.appframe
  82. });
  83. this.frm_head = this.toolbar;
  84. // print layout
  85. this.setup_print_layout();
  86. // 2 column layout
  87. this.setup_std_layout();
  88. // client script must be called after "setup" - there are no fields_dict attached to the frm otherwise
  89. this.script_manager = new wn.ui.form.ScriptManager({
  90. frm: this
  91. });
  92. this.script_manager.setup();
  93. this.watch_model_updates();
  94. this.footer = new wn.ui.form.Footer({
  95. frm: this,
  96. parent: $(this.wrapper).find(".appframe-footer")
  97. })
  98. this.setup_done = true;
  99. }
  100. _f.Frm.prototype.setup_print_layout = function() {
  101. this.print_wrapper = $('<div>\
  102. <div class="print-toolbar row" style="padding-top: 5px; padding-bottom: 5px; margin-top: -15px; \
  103. margin-bottom: 15px; padding-left: 15px; position:relative;">\
  104. <i class="text-muted icon-print" style="position: absolute; top: 13px; left: 10px; "></i>\
  105. <div class="col-xs-3">\
  106. <select class="print-preview-select form-control"></select></div>\
  107. <div class="col-xs-3" style="padding-top: 7px;">\
  108. <input type="checkbox" class="print-letterhead" checked/> Letterhead</div>\
  109. <div class="col-xs-6 text-right" style="padding-top: 7px;">\
  110. <a style="margin-right: 7px;" class="print-print">Print</a>\
  111. <a class="close">×</a>\
  112. </div>\
  113. </div>\
  114. <div class="print-preview">\
  115. </div>\
  116. </div>')
  117. .appendTo(this.layout_main)
  118. .toggle(false);
  119. var me = this;
  120. this.print_wrapper.find(".close").click(function() {
  121. me.hide_print();
  122. });
  123. this.print_formats = wn.meta.get_print_formats(this.meta.name);
  124. this.print_letterhead = this.print_wrapper
  125. .find(".print-letterhead")
  126. .on("change", function() { me.print_sel.trigger("change"); });
  127. this.print_sel = this.print_wrapper
  128. .find(".print-preview-select")
  129. .on("change", function() {
  130. _p.build(me.print_sel.val(), function(html) {
  131. me.print_wrapper.find(".print-preview").html(html);
  132. }, !me.print_letterhead.is(":checked"), true, true);
  133. })
  134. this.print_wrapper.find(".print-print").click(function() {
  135. _p.build(
  136. me.print_sel.val(), // fmtname
  137. _p.go, // onload
  138. !me.print_letterhead.is(":checked") // no_letterhead
  139. );
  140. })
  141. }
  142. _f.Frm.prototype.print_doc = function() {
  143. if(this.print_wrapper.is(":visible")) {
  144. this.hide_print();
  145. return;
  146. }
  147. if(!wn.model.can_print(this.doc.doctype, cur_frm)) {
  148. msgprint(wn._("You are not allowed to Print this document."));
  149. return;
  150. }
  151. if(this.doc.docstatus==2) {
  152. msgprint(wn._("Cannot Print Cancelled Documents."));
  153. return;
  154. }
  155. this.print_wrapper.toggle(true);
  156. this.print_sel
  157. .empty().add_options(this.print_formats)
  158. .trigger("change");
  159. this.form_wrapper.toggle(false);
  160. }
  161. _f.Frm.prototype.hide_print = function() {
  162. if(this.setup_done) {
  163. this.print_wrapper.toggle(false);
  164. this.form_wrapper.toggle(true);
  165. }
  166. }
  167. _f.Frm.prototype.watch_model_updates = function() {
  168. // watch model updates
  169. var me = this;
  170. // on main doc
  171. wn.model.on(me.doctype, "*", function(fieldname, value, doc) {
  172. // set input
  173. if(doc.name===me.docname) {
  174. me.dirty();
  175. me.fields_dict[fieldname]
  176. && me.fields_dict[fieldname].refresh(fieldname);
  177. me.refresh_dependency();
  178. me.script_manager.trigger(fieldname, doc.doctype, doc.name);
  179. }
  180. })
  181. // on table fields
  182. $.each(wn.model.get("DocField", {fieldtype:"Table", parent: me.doctype}), function(i, df) {
  183. wn.model.on(df.options, "*", function(fieldname, value, doc) {
  184. if(doc.parent===me.docname && doc.parentfield===df.fieldname) {
  185. me.dirty();
  186. me.fields_dict[df.fieldname].grid.set_value(fieldname, value, doc);
  187. me.script_manager.trigger(fieldname, doc.doctype, doc.name);
  188. }
  189. })
  190. })
  191. }
  192. _f.Frm.prototype.onhide = function() {
  193. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  194. }
  195. _f.Frm.prototype.setup_std_layout = function() {
  196. this.form_wrapper = $('<div></div>').appendTo(this.layout_main);
  197. this.body_header = $("<div>").appendTo(this.form_wrapper);
  198. this.body = $("<div>").appendTo(this.form_wrapper);
  199. // only tray
  200. this.meta.section_style='Simple'; // always simple!
  201. // layout
  202. this.layout = new wn.ui.form.Layout({
  203. parent: this.body,
  204. doctype: this.doctype,
  205. frm: this,
  206. });
  207. this.layout.make();
  208. this.fields_dict = this.layout.fields_dict;
  209. this.fields = this.layout.fields_list;
  210. this.dashboard = new wn.ui.form.Dashboard({
  211. frm: this,
  212. });
  213. // state
  214. this.states = new wn.ui.form.States({
  215. frm: this
  216. });
  217. }
  218. // email the form
  219. _f.Frm.prototype.email_doc = function(message) {
  220. new wn.views.CommunicationComposer({
  221. doc: this.doc,
  222. subject: wn._(this.meta.name) + ': ' + this.docname,
  223. recipients: this.doc.email || this.doc.email_id || this.doc.contact_email,
  224. attach_document_print: true,
  225. message: message,
  226. real_name: this.doc.real_name || this.doc.contact_display || this.doc.contact_name
  227. });
  228. }
  229. // rename the form
  230. _f.Frm.prototype.rename_doc = function() {
  231. wn.model.rename_doc(this.doctype, this.docname);
  232. }
  233. // notify this form of renamed records
  234. _f.Frm.prototype.rename_notify = function(dt, old, name) {
  235. // from form
  236. if(this.meta.istable)
  237. return;
  238. if(this.docname == old)
  239. this.docname = name;
  240. else
  241. return;
  242. // cleanup
  243. if(this && this.opendocs[old]) {
  244. // delete docfield copy
  245. wn.meta.docfield_copy[dt][name] = wn.meta.docfield_copy[dt][old];
  246. delete wn.meta.docfield_copy[dt][old];
  247. }
  248. delete this.opendocs[old];
  249. this.opendocs[name] = true;
  250. if(this.meta.in_dialog || !this.in_form) {
  251. return;
  252. }
  253. wn.re_route[window.location.hash] = '#Form/' + encodeURIComponent(this.doctype) + '/' + encodeURIComponent(name);
  254. wn.set_route('Form', this.doctype, name);
  255. }
  256. // SETUP
  257. _f.Frm.prototype.setup_meta = function(doctype) {
  258. this.meta = wn.model.get_doc('DocType',this.doctype);
  259. this.perm = wn.perm.get_perm(this.doctype); // for create
  260. if(this.meta.istable) { this.meta.in_dialog = 1 }
  261. }
  262. _f.Frm.prototype.defocus_rest = function() {
  263. // deselect others
  264. if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect();
  265. }
  266. _f.Frm.prototype.refresh_header = function() {
  267. // set title
  268. // main title
  269. if(!this.meta.in_dialog || this.in_form) {
  270. set_title(this.meta.issingle ? this.doctype : this.docname);
  271. }
  272. if(wn.ui.toolbar.recent)
  273. wn.ui.toolbar.recent.add(this.doctype, this.docname, 1);
  274. // show / hide buttons
  275. if(this.frm_head) {
  276. this.frm_head.refresh();
  277. }
  278. }
  279. _f.Frm.prototype.check_doc_perm = function() {
  280. // get perm
  281. var dt = this.parent_doctype?this.parent_doctype : this.doctype;
  282. var dn = this.parent_docname?this.parent_docname : this.docname;
  283. this.perm = wn.perm.get_perm(dt, dn);
  284. if(!this.perm[0].read) {
  285. return 0;
  286. }
  287. return 1
  288. }
  289. _f.Frm.prototype.refresh = function(docname) {
  290. // record switch
  291. if(docname) {
  292. if(this.docname != docname && (!this.meta.in_dialog || this.in_form) &&
  293. !this.meta.istable) {
  294. scroll(0, 0);
  295. this.hide_print();
  296. }
  297. this.docname = docname;
  298. }
  299. cur_frm = this;
  300. if(this.docname) { // document to show
  301. // check permissions
  302. if(!this.check_doc_perm()) return;
  303. // read only (workflow)
  304. this.read_only = wn.workflow.is_read_only(this.doctype, this.docname);
  305. // set the doc
  306. this.doc = wn.model.get_doc(this.doctype, this.docname);
  307. // check if doctype is already open
  308. if (!this.opendocs[this.docname]) {
  309. this.check_doctype_conflict(this.docname);
  310. } else {
  311. if(this.doc && (!this.doc.__unsaved) && this.doc.__last_sync_on &&
  312. (new Date() - this.doc.__last_sync_on) > (this.refresh_if_stale_for * 1000)) {
  313. this.reload_doc();
  314. return;
  315. }
  316. }
  317. // do setup
  318. if(!this.setup_done) this.setup();
  319. // load the record for the first time, if not loaded (call 'onload')
  320. cur_frm.cscript.is_onload = false;
  321. if(!this.opendocs[this.docname]) {
  322. cur_frm.cscript.is_onload = true;
  323. this.setnewdoc();
  324. } else {
  325. this.render_form();
  326. }
  327. }
  328. }
  329. _f.Frm.prototype.render_form = function() {
  330. if(!this.meta.istable) {
  331. // header
  332. this.refresh_header();
  333. // call trigger
  334. this.script_manager.trigger("refresh");
  335. // trigger global trigger
  336. // to use this
  337. $(document).trigger('form_refresh');
  338. // fields
  339. this.refresh_fields();
  340. // call onload post render for callbacks to be fired
  341. if(this.cscript.is_onload) {
  342. this.script_manager.trigger("onload_post_render");
  343. }
  344. // focus on first input
  345. if(this.doc.docstatus==0) {
  346. var first = this.form_wrapper.find('.form-layout-row :input:first');
  347. if(!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
  348. first.focus();
  349. }
  350. }
  351. } else {
  352. this.refresh_header();
  353. }
  354. $(cur_frm.wrapper).trigger('render_complete');
  355. }
  356. _f.Frm.prototype.refresh_field = function(fname) {
  357. cur_frm.fields_dict[fname] && cur_frm.fields_dict[fname].refresh
  358. && cur_frm.fields_dict[fname].refresh();
  359. }
  360. _f.Frm.prototype.refresh_fields = function() {
  361. this.layout.refresh(this.doc);
  362. this.layout.primary_button = $(this.wrapper).find(".btn-primary");
  363. // cleanup activities after refresh
  364. this.cleanup_refresh(this);
  365. // dependent fields
  366. this.refresh_dependency();
  367. }
  368. _f.Frm.prototype.cleanup_refresh = function() {
  369. var me = this;
  370. if(me.fields_dict['amended_from']) {
  371. if (me.doc.amended_from) {
  372. unhide_field('amended_from');
  373. if (me.fields_dict['amendment_date']) unhide_field('amendment_date');
  374. } else {
  375. hide_field('amended_from');
  376. if (me.fields_dict['amendment_date']) hide_field('amendment_date');
  377. }
  378. }
  379. if(me.fields_dict['trash_reason']) {
  380. if(me.doc.trash_reason && me.doc.docstatus == 2) {
  381. unhide_field('trash_reason');
  382. } else {
  383. hide_field('trash_reason');
  384. }
  385. }
  386. if(me.meta.autoname && me.meta.autoname.substr(0,6)=='field:' && !me.doc.__islocal) {
  387. var fn = me.meta.autoname.substr(6);
  388. cur_frm.toggle_display(fn, false);
  389. }
  390. if(me.meta.autoname=="naming_series:" && !me.doc.__islocal) {
  391. cur_frm.toggle_display("naming_series", false);
  392. }
  393. }
  394. // Resolve "depends_on" and show / hide accordingly
  395. _f.Frm.prototype.refresh_dependency = function() {
  396. var me = this;
  397. var doc = locals[this.doctype][this.docname];
  398. // build dependants' dictionary
  399. var has_dep = false;
  400. for(fkey in me.fields) {
  401. var f = me.fields[fkey];
  402. f.dependencies_clear = true;
  403. if(f.df.depends_on) {
  404. has_dep = true;
  405. }
  406. }
  407. if(!has_dep)return;
  408. // show / hide based on values
  409. for(var i=me.fields.length-1;i>=0;i--) {
  410. var f = me.fields[i];
  411. f.guardian_has_value = true;
  412. if(f.df.depends_on) {
  413. // evaluate guardian
  414. var v = doc[f.df.depends_on];
  415. if(f.df.depends_on.substr(0,5)=='eval:') {
  416. f.guardian_has_value = eval(f.df.depends_on.substr(5));
  417. } else if(f.df.depends_on.substr(0,3)=='fn:') {
  418. f.guardian_has_value = me.script_manager.trigger(f.df.depends_on.substr(3), me.doctype, me.docname);
  419. } else {
  420. if(!v) {
  421. f.guardian_has_value = false;
  422. }
  423. }
  424. // show / hide
  425. if(f.guardian_has_value) {
  426. if(f.df.hidden_due_to_dependency) {
  427. f.df.hidden_due_to_dependency = false;
  428. f.refresh();
  429. }
  430. } else {
  431. if(!f.df.hidden_due_to_dependency) {
  432. f.df.hidden_due_to_dependency = true;
  433. f.refresh();
  434. }
  435. }
  436. }
  437. }
  438. this.layout.refresh_section_count();
  439. }
  440. _f.Frm.prototype.setnewdoc = function() {
  441. // moved this call to refresh function
  442. // this.check_doctype_conflict(docname);
  443. var me = this;
  444. this.script_manager.trigger("before_load", this.doctype, this.docname, function() {
  445. me.script_manager.trigger("onload");
  446. me.opendocs[me.docname] = true;
  447. me.render_form();
  448. })
  449. }
  450. _f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) {
  451. var me = this;
  452. if(this.docname) {
  453. // make doc list
  454. var doclist = wn.model.compress(make_doclist(this.doctype, this.docname));
  455. // send to run
  456. if(callingfield)
  457. $(callingfield.input).set_working();
  458. return $c('runserverobj', {'docs':doclist, 'method':scriptname },
  459. function(r, rtxt) {
  460. // run refresh
  461. if(onrefresh)
  462. onrefresh(r,rtxt);
  463. // fields
  464. me.refresh_fields();
  465. // enable button
  466. if(callingfield)
  467. $(callingfield.input).done_working();
  468. }
  469. );
  470. }
  471. }
  472. _f.Frm.prototype.copy_doc = function(onload, from_amend) {
  473. if(!this.perm[0].create) {
  474. msgprint('You are not allowed to create '+this.meta.name);
  475. return;
  476. }
  477. var dn = this.docname;
  478. // copy parent
  479. var newdoc = wn.model.copy_doc(this.doctype, dn, from_amend);
  480. // copy chidren
  481. var dl = make_doclist(this.doctype, dn);
  482. // table fields dict - for no_copy check
  483. var tf_dict = {};
  484. for(var d in dl) {
  485. d1 = dl[d];
  486. // get tabel field
  487. if(d1.parentfield && !tf_dict[d1.parentfield]) {
  488. tf_dict[d1.parentfield] = wn.meta.get_docfield(d1.parenttype, d1.parentfield);
  489. }
  490. if(d1.parent==dn && cint(tf_dict[d1.parentfield].no_copy)!=1) {
  491. var ch = wn.model.copy_doc(d1.doctype, d1.name, from_amend);
  492. ch.parent = newdoc.name;
  493. ch.docstatus = 0;
  494. ch.owner = user;
  495. ch.creation = '';
  496. ch.modified_by = user;
  497. ch.modified = '';
  498. }
  499. }
  500. newdoc.__islocal = 1;
  501. newdoc.docstatus = 0;
  502. newdoc.owner = user;
  503. newdoc.creation = '';
  504. newdoc.modified_by = user;
  505. newdoc.modified = '';
  506. if(onload)onload(newdoc);
  507. loaddoc(newdoc.doctype, newdoc.name);
  508. }
  509. _f.Frm.prototype.reload_doc = function() {
  510. this.check_doctype_conflict(this.docname);
  511. var me = this;
  512. var onsave = function(r, rtxt) {
  513. me.refresh();
  514. }
  515. if(!me.doc.__islocal) {
  516. wn.model.remove_from_locals(me.doctype, me.docname);
  517. wn.model.with_doc(me.doctype, me.docname, function() {
  518. me.refresh();
  519. })
  520. }
  521. }
  522. var validated;
  523. _f.Frm.prototype.save = function(save_action, callback, btn, on_error) {
  524. $(document.activeElement).blur();
  525. // let any pending js process finish
  526. var me = this;
  527. setTimeout(function() { me._save(save_action, callback, btn, on_error) }, 100);
  528. }
  529. _f.Frm.prototype._save = function(save_action, callback, btn, on_error) {
  530. var me = this;
  531. if((!this.meta.in_dialog || this.in_form) && !this.meta.istable)
  532. scroll(0, 0);
  533. // validate
  534. if(save_action!="Cancel") {
  535. validated = true;
  536. this.script_manager.trigger("validate");
  537. if(!validated) {
  538. if(on_error)
  539. on_error();
  540. return;
  541. }
  542. }
  543. var doclist = new wn.model.DocList(this.doctype, this.docname);
  544. doclist.save(save_action || "Save", function(r) {
  545. if(!r.exc) {
  546. me.refresh();
  547. } else {
  548. if(on_error)
  549. on_error();
  550. }
  551. callback && callback(r);
  552. if(wn._from_link) {
  553. if(me.doctype===wn._from_link.df.options) {
  554. wn._from_link.parse_validate_and_set_in_model(me.docname);
  555. wn.set_route("Form", wn._from_link.frm.doctype, wn._from_link.frm.docname);
  556. setTimeout(function() { scroll(0, wn._from_link_scrollY); }, 100);
  557. }
  558. wn._from_link = null;
  559. }
  560. }, btn);
  561. }
  562. _f.Frm.prototype.savesubmit = function(btn, on_error) {
  563. var me = this;
  564. wn.confirm("Permanently Submit "+this.docname+"?", function() {
  565. validated = true;
  566. me.script_manager.trigger("before_submit");
  567. if(!validated) {
  568. if(on_error)
  569. on_error();
  570. return;
  571. }
  572. me.save('Submit', function(r) {
  573. if(!r.exc) {
  574. me.script_manager.trigger("on_submit");
  575. }
  576. }, btn, on_error);
  577. });
  578. }
  579. _f.Frm.prototype.savecancel = function(btn, on_error) {
  580. var me = this;
  581. wn.confirm("Permanently Cancel "+this.docname+"?", function() {
  582. validated = true;
  583. me.script_manager.trigger("before_cancel");
  584. if(!validated) {
  585. if(on_error)
  586. on_error();
  587. return;
  588. }
  589. var doclist = new wn.model.DocList(me.doctype, me.docname);
  590. doclist.cancel(function(r) {
  591. if(!r.exc) {
  592. me.refresh();
  593. me.script_manager.trigger("after_cancel");
  594. }
  595. }, btn, on_error);
  596. });
  597. }
  598. // delete the record
  599. _f.Frm.prototype.savetrash = function() {
  600. wn.model.delete_doc(this.doctype, this.docname, function(r) {
  601. window.history.back();
  602. })
  603. }
  604. _f.Frm.prototype.amend_doc = function() {
  605. if(!this.fields_dict['amended_from']) {
  606. alert('"amended_from" field must be present to do an amendment.');
  607. return;
  608. }
  609. var me = this;
  610. var fn = function(newdoc) {
  611. newdoc.amended_from = me.docname;
  612. if(me.fields_dict && me.fields_dict['amendment_date'])
  613. newdoc.amendment_date = dateutil.obj_to_str(new Date());
  614. }
  615. this.copy_doc(fn, 1);
  616. }
  617. _f.Frm.prototype.disable_save = function() {
  618. // IMPORTANT: this function should be called in refresh event
  619. this.save_disabled = true;
  620. this.appframe.set_title_right("", null);
  621. }
  622. _f.Frm.prototype.save_or_update = function() {
  623. if(this.save_disabled) return;
  624. if(this.doc.docstatus===0) {
  625. this.save();
  626. } else if(this.doc.docstatus===1 && this.doc.__unsaved) {
  627. this.save("Update");
  628. }
  629. }
  630. _f.get_value = function(dt, dn, fn) {
  631. if(locals[dt] && locals[dt][dn])
  632. return locals[dt][dn][fn];
  633. }
  634. _f.Frm.prototype.dirty = function() {
  635. this.doc.__unsaved = 1;
  636. $(this.wrapper).trigger('dirty')
  637. }
  638. _f.Frm.prototype.get_docinfo = function() {
  639. return wn.model.docinfo[this.doctype][this.docname];
  640. }
  641. _f.Frm.prototype.get_perm = function(permlevel, access_type) {
  642. return this.perm[permlevel] ? this.perm[permlevel][access_type] : null;
  643. }
  644. _f.Frm.prototype.set_intro = function(txt) {
  645. wn.utils.set_intro(this, this.body, txt);
  646. }
  647. _f.Frm.prototype.set_footnote = function(txt) {
  648. wn.utils.set_footnote(this, this.body, txt);
  649. }
  650. _f.Frm.prototype.add_custom_button = function(label, fn, icon) {
  651. return this.appframe.add_primary_action(label, fn, icon || "icon-arrow-right");
  652. }
  653. _f.Frm.prototype.clear_custom_buttons = function() {
  654. this.toolbar.refresh()
  655. }
  656. _f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) {
  657. if(!this.fetch_dict[link_field]) {
  658. this.fetch_dict[link_field] = {'columns':[], 'fields':[]}
  659. }
  660. this.fetch_dict[link_field].columns.push(src_field);
  661. this.fetch_dict[link_field].fields.push(tar_field);
  662. }
  663. _f.Frm.prototype.set_print_heading = function(txt) {
  664. this.pformat[cur_frm.docname] = txt;
  665. }