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 28 KiB

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