Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

form.js 28 KiB

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