Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

1213 Zeilen
32 KiB

  1. // fields.js
  2. //
  3. // Fields are divided into 2 types
  4. // 1. Standard fields are loaded with the libarary
  5. // 2. Special fields are loaded with form.compressed.js
  6. //
  7. //
  8. // + wrapper
  9. // + input_area
  10. // + display_area
  11. // ======================================================================================
  12. var no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image'];
  13. var codeid=0; var code_editors={};
  14. function Field() {
  15. this.with_label = 1;
  16. }
  17. Field.prototype.make_body = function() {
  18. var ischk = (this.df.fieldtype=='Check' ? 1 : 0);
  19. // parent element
  20. if(this.parent)
  21. this.wrapper = $a(this.parent, 'div');
  22. else
  23. this.wrapper = document.createElement('div');
  24. this.label_area = $a(this.wrapper, 'div', '', {margin:'8px 0px 2px 0px'});
  25. if(ischk && !this.in_grid) {
  26. this.input_area = $a(this.label_area, 'span', '', {marginRight:'4px'});
  27. this.disp_area = $a(this.label_area, 'span', '', {marginRight:'4px'});
  28. }
  29. // label
  30. if(this.with_label) {
  31. this.label_span = $a(this.label_area, 'span', 'field_label')
  32. // error icon
  33. this.label_icon = $a(this.label_area,'img','',{margin:'-3px 4px -3px 4px'}); $dh(this.label_icon);
  34. this.label_icon.src = 'images/icons/error.gif';
  35. this.label_icon.title = 'Mandatory value needs to be entered';
  36. // error icon
  37. this.suggest_icon = $a(this.label_area,'img','',{margin:'-3px 4px -3px 0px'}); $dh(this.suggest_icon);
  38. this.suggest_icon.src = 'images/icons/bullet_arrow_down.png';
  39. this.suggest_icon.title = 'With suggestions';
  40. } else {
  41. this.label_span = $a(this.label_area, 'span', '', {marginRight:'4px'})
  42. $dh(this.label_area);
  43. }
  44. // make the input areas
  45. if(!this.input_area) {
  46. this.input_area = $a(this.wrapper, 'div');
  47. this.disp_area = $a(this.wrapper, 'div');
  48. }
  49. // apply style
  50. if(this.in_grid) {
  51. if(this.label_area) $dh(this.label_area);
  52. } else {
  53. this.input_area.className = 'input_area';
  54. $y(this.wrapper,{marginBottom:'4px'});
  55. // set description
  56. this.set_description();
  57. }
  58. // bind label refresh
  59. if(this.onmake)this.onmake();
  60. }
  61. Field.prototype.set_max_width = function() {
  62. var no_max = ['Code', 'Text Editor', 'Text', 'Table', 'HTML']
  63. if(this.wrapper && this.layout_cell && this.layout_cell.parentNode.cells
  64. && this.layout_cell.parentNode.cells.length==1 && !in_list(no_max, this.df.fieldtype)) {
  65. $y(this.wrapper, {paddingRight:'50%'});
  66. }
  67. }
  68. Field.prototype.set_label = function() {
  69. if(this.with_label && this.label_area && this.label!=this.df.label) {
  70. this.label_span.innerHTML = this.df.label;this.label = this.df.label;
  71. }
  72. }
  73. Field.prototype.set_description = function() {
  74. if(this.df.description) {
  75. // parent
  76. var p = in_list(['Text Editor', 'Code', 'Check'], this.df.fieldtype) ? this.label_area : this.wrapper;
  77. this.desc_area = $a(p, 'div', 'field_description', '', this.df.description)
  78. // padding on the bottom
  79. if(in_list(['Text Editor', 'Code'], this.df.fieldtype))
  80. $(this.desc_area).addClass('field_description_top');
  81. }
  82. }
  83. // Field Refresh
  84. // --------------------------------------------------------------------------------------------
  85. Field.prototype.get_status = function() {
  86. // if used in filters
  87. if(this.in_filter) this.not_in_form = this.in_filter;
  88. if(this.not_in_form) {
  89. return 'Write';
  90. }
  91. var fn = this.df.fieldname?this.df.fieldname:this.df.label;
  92. this.df = get_field(this.doctype, fn, this.docname);
  93. if(!this.df.permlevel) this.df.permlevel = 0;
  94. var p = this.perm[this.df.permlevel];
  95. var ret;
  96. // permission level
  97. if(cur_frm.editable && p && p[WRITE])ret='Write';
  98. else if(p && p[READ])ret='Read';
  99. else ret='None';
  100. // binary
  101. if(this.df.fieldtype=='Binary')
  102. ret = 'None'; // no display for binary
  103. // hidden
  104. if(cint(this.df.hidden))
  105. ret = 'None';
  106. // for submit
  107. if(ret=='Write' && cint(cur_frm.doc.docstatus) > 0) ret = 'Read';
  108. // allow on submit
  109. var a_o_s = cint(this.df.allow_on_submit);
  110. if(a_o_s && (this.in_grid || (this.frm && this.frm.not_in_container))) {
  111. a_o_s = null;
  112. if(this.in_grid) a_o_s = this.grid.field.df.allow_on_submit; // take from grid
  113. if(this.frm && this.frm.not_in_container) { a_o_s = cur_grid.field.df.allow_on_submit;} // take from grid
  114. }
  115. if(cur_frm.editable && a_o_s && cint(cur_frm.doc.docstatus)>0 && !this.df.hidden) {
  116. tmp_perm = get_perm(cur_frm.doctype, cur_frm.docname, 1);
  117. if(tmp_perm[this.df.permlevel] && tmp_perm[this.df.permlevel][WRITE])ret='Write';
  118. }
  119. return ret;
  120. }
  121. Field.prototype.set_style_mandatory = function(add) {
  122. if(add) {
  123. $(this.txt ? this.txt : this.input).addClass('input-mandatory');
  124. if(this.disp_area) $(this.disp_area).addClass('input-mandatory');
  125. } else {
  126. $(this.txt ? this.txt : this.input).removeClass('input-mandatory');
  127. if(this.disp_area) $(this.disp_area).removeClass('input-mandatory');
  128. }
  129. }
  130. Field.prototype.refresh_mandatory = function() {
  131. if(this.in_filter)return;
  132. // mandatory changes
  133. if(this.df.reqd) {
  134. if(this.label_area) this.label_area.style.color= "#d22";
  135. this.set_style_mandatory(1);
  136. } else {
  137. if(this.label_area) this.label_area.style.color= "#222";
  138. this.set_style_mandatory(0);
  139. }
  140. this.refresh_label_icon()
  141. this.set_reqd = this.df.reqd;
  142. }
  143. Field.prototype.refresh_display = function() {
  144. // from permission
  145. if(!this.set_status || this.set_status!=this.disp_status) { // status changed
  146. if(this.disp_status=='Write') { // write
  147. if(this.make_input&&(!this.input)) { // make input if reqd
  148. this.make_input();
  149. if(this.onmake_input) this.onmake_input();
  150. }
  151. if(this.show) this.show()
  152. else { $ds(this.wrapper); }
  153. // input or content
  154. if(this.input) { // if there, show it!
  155. $ds(this.input_area);
  156. $dh(this.disp_area);
  157. if(this.input.refresh)this.input.refresh();
  158. } else { // no widget
  159. $dh(this.input_area);
  160. $ds(this.disp_area);
  161. }
  162. } else if(this.disp_status=='Read') {
  163. // read
  164. if(this.show) this.show()
  165. else { $ds(this.wrapper); }
  166. $dh(this.input_area);
  167. $ds(this.disp_area);
  168. } else {
  169. // None - hide all
  170. if(this.hide) this.hide();
  171. else $dh(this.wrapper);
  172. }
  173. this.set_status = this.disp_status;
  174. }
  175. }
  176. Field.prototype.refresh = function() {
  177. // get status
  178. this.disp_status = this.get_status();
  179. // if there is a special refresh in case of table, then this is not valid
  180. if(this.in_grid
  181. && this.table_refresh
  182. && this.disp_status == 'Write')
  183. { this.table_refresh(); return; }
  184. this.set_label();
  185. this.refresh_display();
  186. // further refresh
  187. if(this.onrefresh) this.onrefresh();
  188. if(this.input&&this.input.refresh) this.input.refresh(this.df);
  189. if(!this.not_in_form)
  190. this.set_input(_f.get_value(this.doctype,this.docname,this.df.fieldname));
  191. this.refresh_mandatory();
  192. this.set_max_width();
  193. }
  194. Field.prototype.refresh_label_icon = function() {
  195. // mandatory
  196. if(this.df.reqd) {
  197. if(this.get_value && is_null(this.get_value())) {
  198. if(this.label_icon) $ds(this.label_icon);
  199. $(this.txt ? this.txt : this.input).addClass('field-to-update')
  200. } else {
  201. if(this.label_icon) $dh(this.label_icon);
  202. $(this.txt ? this.txt : this.input).removeClass('field-to-update')
  203. }
  204. }
  205. }
  206. // Set / display values
  207. // --------------------------------------------------------------------------------------------
  208. Field.prototype.set = function(val) {
  209. // not in form
  210. if(this.not_in_form)
  211. return;
  212. if((!this.docname) && this.grid) {
  213. this.docname = this.grid.add_newrow(); // new row
  214. }
  215. // cleanup ms word quotes
  216. if(in_list(['Data','Text','Small Text','Code'], this.df.fieldtype))
  217. val = clean_smart_quotes(val);
  218. var set_val = val;
  219. if(this.validate)set_val = this.validate(val);
  220. _f.set_value(this.doctype, this.docname, this.df.fieldname, set_val);
  221. this.value = val; // for return
  222. }
  223. Field.prototype.set_input = function(val) {
  224. this.value = val;
  225. if(this.input&&this.input.set_input) {
  226. if(val==null)this.input.set_input('');
  227. else this.input.set_input(val); // in widget
  228. }
  229. var disp_val = val;
  230. if(val==null) disp_val = '';
  231. this.set_disp(disp_val); // text
  232. }
  233. Field.prototype.run_trigger = function() {
  234. // update mandatory icon
  235. this.refresh_label_icon();
  236. if(this.df.reqd && this.get_value && !is_null(this.get_value()) && this.set_as_error)
  237. this.set_as_error(0);
  238. if(this.not_in_form) {
  239. return;
  240. }
  241. if(cur_frm.cscript[this.df.fieldname])
  242. cur_frm.runclientscript(this.df.fieldname, this.doctype, this.docname);
  243. cur_frm.refresh_dependency();
  244. }
  245. Field.prototype.set_disp_html = function(t) {
  246. if(this.disp_area){
  247. $(this.disp_area).addClass('disp_area');
  248. this.disp_area.innerHTML = (t==null ? '' : t);
  249. if(!t) $(this.disp_area).addClass('disp_area_no_val');
  250. }
  251. }
  252. Field.prototype.set_disp = function(val) {
  253. this.set_disp_html(val);
  254. }
  255. Field.prototype.set_as_error = function(set) {
  256. if(this.in_grid || this.in_filter) return;
  257. var w = this.txt ? this.txt : this.input;
  258. if(set) {
  259. $y(w, {border: '2px solid RED'});
  260. } else {
  261. $y(w, {border: '1px solid #888'});
  262. }
  263. }
  264. // Show in GRID
  265. // --------------------------------------------------------------------------------------------
  266. // for grids (activate against a particular record in the table
  267. Field.prototype.activate = function(docname) {
  268. this.docname = docname;
  269. this.refresh();
  270. if(this.input) {
  271. this.input.isactive = true;
  272. var v = _f.get_value(this.doctype, this.docname, this.df.fieldname);
  273. this.last_value=v;
  274. // set input value
  275. if(this.input.onchange && this.input.get_value && this.input.get_value() !=v) {
  276. if(this.validate)
  277. this.input.set_value(this.validate(v));
  278. else
  279. this.input.set_value((v==null)?'':v);
  280. if(this.format_input)
  281. this.format_input();
  282. }
  283. if(this.input.focus){
  284. try{this.input.focus();} catch(e){} // IE Fix - Unexpected call???
  285. }
  286. }
  287. if(this.txt) {
  288. try{this.txt.focus();} catch(e){} // IE Fix - Unexpected call???
  289. this.txt.isactive = true;
  290. if(this.btn)this.btn.isactive = true;
  291. this.txt.field_object = this;
  292. }
  293. }
  294. // ======================================================================================
  295. function DataField() { } DataField.prototype = new Field();
  296. DataField.prototype.make_input = function() {
  297. var me = this;
  298. this.input = $a(this.input_area, 'input');
  299. if(this.df.fieldtype=='Password') {
  300. if(isIE) {
  301. this.input_area.innerHTML = '<input type="password">'; // IE fix
  302. this.input = this.input_area.childNodes[0];
  303. } else {
  304. this.input.setAttribute('type', 'password');
  305. }
  306. }
  307. this.get_value= function() {
  308. var v = this.input.value;
  309. if(this.validate)v = this.validate(v);
  310. return v;
  311. }
  312. this.input.name = this.df.fieldname;
  313. this.input.onchange = function() {
  314. if(!me.last_value)me.last_value='';
  315. if(me.validate)
  316. me.input.value = me.validate(me.input.value);
  317. me.set(me.input.value);
  318. if(me.format_input)
  319. me.format_input();
  320. if(in_list(['Currency','Float','Int'], me.df.fieldtype)) {
  321. if(flt(me.last_value)==flt(me.input.value)) {
  322. me.last_value = me.input.value;
  323. return; // do not run trigger
  324. }
  325. }
  326. me.last_value = me.input.value;
  327. me.run_trigger();
  328. }
  329. this.input.set_input = function(val) {
  330. if(val==null)val='';
  331. me.input.value = val;
  332. if(me.format_input)me.format_input();
  333. }
  334. // autosuggest type fields
  335. // -----------------------
  336. if(this.df.options=='Suggest') {
  337. wn.require('lib/js/legacy/widgets/autosuggest.js');
  338. // add auto suggest
  339. if(this.suggest_icon) $di(this.suggest_icon);
  340. this.set_get_query = function() { }
  341. this.get_query = function(doc, dt, dn) {
  342. return repl('SELECT DISTINCT `%(fieldname)s` FROM `tab%(dt)s` WHERE `%(fieldname)s` LIKE "%s" LIMIT 50', {fieldname:me.df.fieldname, dt:me.df.parent})
  343. }
  344. var opts = {
  345. script: '',
  346. json: true,
  347. maxresults: 10,
  348. link_field: this
  349. };
  350. this.as = new AutoSuggest(this.input, opts);
  351. }
  352. }
  353. DataField.prototype.validate = function(v) {
  354. if(this.df.options == 'Phone') {
  355. if(v+''=='')return '';
  356. v1 = ''
  357. // phone may start with + and must only have numbers later, '-' and ' ' are stripped
  358. v = v.replace(/ /g, '').replace(/-/g, '').replace(/\(/g, '').replace(/\)/g, '');
  359. // allow initial +,0,00
  360. if(v && v.substr(0,1)=='+') {
  361. v1 = '+'; v = v.substr(1);
  362. }
  363. if(v && v.substr(0,2)=='00') {
  364. v1 += '00'; v = v.substr(2);
  365. }
  366. if(v && v.substr(0,1)=='0') {
  367. v1 += '0'; v = v.substr(1);
  368. }
  369. v1 += cint(v) + '';
  370. return v1;
  371. } else if(this.df.options == 'Email') {
  372. if(v+''=='')return '';
  373. if(!validate_email(v)) {
  374. msgprint(this.df.label + ': ' + v + ' is not a valid email id');
  375. return '';
  376. } else
  377. return v;
  378. } else {
  379. return v;
  380. }
  381. }
  382. DataField.prototype.onrefresh = function() {
  383. if(this.input&&this.df.colour) {
  384. var col = '#'+this.df.colour.split(':')[1];
  385. $bg(this.input,col);
  386. }
  387. }
  388. // ======================================================================================
  389. function ReadOnlyField() { }
  390. ReadOnlyField.prototype = new Field();
  391. // ======================================================================================
  392. function HTMLField() { }
  393. HTMLField.prototype = new Field();
  394. HTMLField.prototype.with_label = 0;
  395. HTMLField.prototype.set_disp = function(val) { this.disp_area.innerHTML = val; }
  396. HTMLField.prototype.set_input = function(val) { if(val) this.set_disp(val); }
  397. HTMLField.prototype.onrefresh = function() { this.set_disp(this.df.options?this.df.options:''); }
  398. // ======================================================================================
  399. var datepicker_active = 0;
  400. function DateField() { } DateField.prototype = new Field();
  401. DateField.prototype.make_input = function() {
  402. var me = this;
  403. this.user_fmt = locals['Control Panel']['Control Panel'].date_format;
  404. if(!this.user_fmt)this.user_fmt = 'dd-mm-yy';
  405. this.input = $a(this.input_area, 'input');
  406. $(this.input).datepicker({
  407. dateFormat: me.user_fmt.replace('yyyy','yy'),
  408. altFormat:'yy-mm-dd',
  409. changeYear: true,
  410. beforeShow: function(input, inst) {
  411. datepicker_active = 1
  412. },
  413. onClose: function(dateText, inst) {
  414. datepicker_active = 0;
  415. if(_f.cur_grid_cell)
  416. _f.cur_grid_cell.grid.cell_deselect();
  417. }
  418. });
  419. var me = this;
  420. me.input.onchange = function() {
  421. // input as dd-mm-yyyy
  422. if(this.value==null)this.value='';
  423. if(!this.not_in_form)
  424. me.set(dateutil.user_to_str(me.input.value));
  425. me.run_trigger();
  426. }
  427. me.input.set_input = function(val) {
  428. if(val==null)val='';
  429. else val=dateutil.str_to_user(val);
  430. me.input.value = val;
  431. }
  432. me.get_value = function() {
  433. if(me.input.value)
  434. return dateutil.user_to_str(me.input.value);
  435. }
  436. }
  437. DateField.prototype.set_disp = function(val) {
  438. var v = dateutil.str_to_user(val);
  439. if(v==null)v = '';
  440. this.set_disp_html(v);
  441. }
  442. DateField.prototype.validate = function(v) {
  443. if(!v) return;
  444. var me = this;
  445. this.clear = function() {
  446. msgprint ("Date must be in format " + this.user_fmt);
  447. me.input.set_input('');
  448. return '';
  449. }
  450. var t = v.split('-');
  451. if(t.length!=3) { return this.clear(); }
  452. else if(cint(t[1])>12 || cint(t[1])<1) { return this.clear(); }
  453. else if(cint(t[2])>31 || cint(t[2])<1) { return this.clear(); }
  454. return v;
  455. };
  456. // ======================================================================================
  457. // for ensuring in AutoSuggest that 2 values are not set in quick succession due to un intentional event call
  458. var _link_onchange_flag = null;
  459. // reference when a new record is created via link
  460. function LinkField() { } LinkField.prototype = new Field();
  461. LinkField.prototype.make_input = function() {
  462. var me = this;
  463. if(me.df.no_buttons) {
  464. this.txt = $a(this.input_area, 'input');
  465. this.input = this.txt;
  466. } else {
  467. makeinput_popup(this, 'ic-zoom', 'ic-sq_next', 'ic-sq_plus');
  468. // setup buttons
  469. me.setup_buttons();
  470. me.onrefresh = function() {
  471. if(me.can_create && cur_frm.doc.docstatus==0) $ds(me.btn2);
  472. else $dh(me.btn2);
  473. }
  474. }
  475. me.txt.field_object = this;
  476. // set onchange triggers
  477. me.set_onchange();
  478. me.input.set_input = function(val) {
  479. if(val==undefined)val='';
  480. me.txt.value = val;
  481. }
  482. me.get_value = function() { return me.txt.value; }
  483. wn.require('lib/js/legacy/widgets/autosuggest.js');
  484. // add auto suggest
  485. var opts = {
  486. script: '',
  487. json: true,
  488. maxresults: 10,
  489. link_field: me
  490. };
  491. this.as = new AutoSuggest(me.txt, opts);
  492. }
  493. LinkField.prototype.setup_buttons = function() {
  494. var me = this;
  495. // magnifier - search
  496. me.btn.onclick = function() {
  497. selector.set(me, me.df.options, me.df.label);
  498. selector.show(me.txt);
  499. }
  500. // open
  501. if(me.btn1)me.btn1.onclick = function() {
  502. if(me.txt.value && me.df.options) { loaddoc(me.df.options, me.txt.value); }
  503. }
  504. // add button - for inline creation of records
  505. me.can_create = 0;
  506. if((!me.not_in_form) && in_list(profile.can_create, me.df.options)) {
  507. me.can_create = 1;
  508. me.btn2.onclick = function() {
  509. var on_save_callback = function(new_rec) {
  510. if(new_rec) {
  511. var d = _f.calling_doc_stack.pop(); // patch for composites
  512. locals[d[0]][d[1]][me.df.fieldname] = new_rec;
  513. me.refresh();
  514. if(me.grid)me.grid.refresh();
  515. // call script
  516. me.run_trigger();
  517. }
  518. }
  519. _f.calling_doc_stack.push([me.doctype, me.docname]);
  520. new_doc(me.df.options, me.on_new, 1, on_save_callback, me.doctype, me.docname, me.frm.not_in_container);
  521. }
  522. } else {
  523. $dh(me.btn2); $y($td(me.tab,0,2), {width:'0px'});
  524. }
  525. }
  526. LinkField.prototype.set_onchange = function() {
  527. var me = this;
  528. me.txt.onchange = function(e) {
  529. if(cur_autosug)return; // still setting value
  530. // check values are not set in quick succession due to un-intentional event call
  531. if(_link_onchange_flag) { return;}
  532. _link_onchange_flag = 1;
  533. // refresh mandatory style
  534. me.refresh_label_icon();
  535. // not in form, do nothing
  536. if(me.not_in_form) {
  537. _link_onchange_flag = 0;
  538. return;
  539. }
  540. // same value, do nothing
  541. if(cur_frm) {
  542. if(me.txt.value == locals[me.doctype][me.docname][me.df.fieldname]) {
  543. me.set(me.txt.value); // one more time, grid bug?
  544. me.run_trigger(); // wanted - called as refresh?
  545. setTimeout('_link_onchange_flag = 0', 500);
  546. return;
  547. }
  548. }
  549. me.set(me.txt.value);
  550. // deselect cell if in grid
  551. if(_f.cur_grid_cell)
  552. _f.cur_grid_cell.grid.cell_deselect();
  553. // run trigger if value is cleared
  554. if(!me.txt.value) {
  555. me.run_trigger();
  556. setTimeout('_link_onchange_flag = 0', 500);
  557. return;
  558. }
  559. // validate the value just entered
  560. var fetch = '';
  561. if(cur_frm.fetch_dict[me.df.fieldname])
  562. fetch = cur_frm.fetch_dict[me.df.fieldname].columns.join(', ');
  563. $c('webnotes.widgets.form.validate_link', {'value':me.txt.value, 'options':me.df.options, 'fetch': fetch}, function(r,rt) {
  564. setTimeout('_link_onchange_flag = 0', 500);
  565. if(selector && selector.display) return; // selecting from popup
  566. if(r.message=='Ok') {
  567. // set fetch values
  568. if(r.fetch_values) me.set_fetch_values(r.fetch_values);
  569. me.run_trigger();
  570. } else {
  571. var astr = '';
  572. if(in_list(profile.can_create, me.df.options)) astr = repl('<br><br><span class="link_type" onclick="newdoc(\'%(dt)s\')">Click here</span> to create a new %(dtl)s', {dt:me.df.options, dtl:get_doctype_label(me.df.options)})
  573. msgprint(repl('error:<b>%(val)s</b> is not a valid %(dt)s.<br><br>You must first create a new %(dt)s <b>%(val)s</b> and then select its value. To find an existing %(dt)s, click on the magnifying glass next to the field.%(add)s', {val:me.txt.value, dt:get_doctype_label(me.df.options), add:astr}));
  574. me.txt.value = '';
  575. me.set('');
  576. }
  577. });
  578. }
  579. }
  580. LinkField.prototype.set_fetch_values = function(fetch_values) {
  581. var fl = cur_frm.fetch_dict[this.df.fieldname].fields;
  582. var changed_fields = [];
  583. for(var i=0; i< fl.length; i++) {
  584. if(locals[this.doctype][this.docname][fl[i]]!=fetch_values[i]) {
  585. locals[this.doctype][this.docname][fl[i]] = fetch_values[i];
  586. if(!this.grid) {
  587. refresh_field(fl[i]);
  588. // call trigger on the target field
  589. changed_fields.push(fl[i]);
  590. }
  591. }
  592. }
  593. // run triggers
  594. for(i=0; i<changed_fields.length; i++) {
  595. if(cur_frm.fields_dict[changed_fields[i]]) // on main
  596. cur_frm.fields_dict[changed_fields[i]].run_trigger();
  597. }
  598. // refresh grid
  599. if(this.grid) this.grid.refresh();
  600. }
  601. LinkField.prototype.set_get_query = function() {
  602. if(this.get_query)return;
  603. if(this.grid) {
  604. var f = this.grid.get_field(this.df.fieldname);
  605. if(f.get_query) this.get_query = f.get_query;
  606. }
  607. }
  608. LinkField.prototype.set_disp = function(val) {
  609. var t = null;
  610. if(val)t = "<a href=\'javascript:loaddoc(\""+this.df.options+"\", \""+val+"\")\'>"+val+"</a>";
  611. this.set_disp_html(t);
  612. }
  613. // ======================================================================================
  614. function IntField() { } IntField.prototype = new DataField();
  615. IntField.prototype.validate = function(v) {
  616. if(isNaN(parseInt(v)))return null;
  617. return cint(v);
  618. };
  619. IntField.prototype.format_input = function() {
  620. if(this.input.value==null) this.input.value='';
  621. }
  622. // ======================================================================================
  623. function FloatField() { } FloatField.prototype = new DataField();
  624. FloatField.prototype.validate = function(v) {
  625. var v= parseFloat(v); if(isNaN(v))return null;
  626. return v;
  627. };
  628. FloatField.prototype.format_input = function() {
  629. if(this.input.value==null) this.input.value='';
  630. }
  631. // ======================================================================================
  632. function CurrencyField() { } CurrencyField.prototype = new DataField();
  633. CurrencyField.prototype.format_input = function() {
  634. var v = fmt_money(this.input.value);
  635. if(this.not_in_form) {
  636. if(!flt(this.input.value)) v = ''; // blank in filter
  637. }
  638. this.input.value = v;
  639. }
  640. CurrencyField.prototype.validate = function(v) {
  641. if(v==null || v=='')
  642. return 0;
  643. return flt(v,2);
  644. }
  645. CurrencyField.prototype.set_disp = function(val) {
  646. var v = fmt_money(val);
  647. this.set_disp_html(v);
  648. }
  649. CurrencyField.prototype.onmake_input = function() {
  650. if(!this.input) return;
  651. this.input.onfocus = function() {
  652. if(flt(this.value)==0)this.select();
  653. }
  654. }
  655. // ======================================================================================
  656. function CheckField() { } CheckField.prototype = new Field();
  657. CheckField.prototype.validate = function(v) {
  658. var v= parseInt(v); if(isNaN(v))return 0;
  659. return v;
  660. };
  661. CheckField.prototype.onmake = function() {
  662. this.checkimg = $a(this.disp_area, 'div');
  663. var img = $a(this.checkimg, 'img');
  664. img.src = 'images/ui/tick.gif';
  665. $dh(this.checkimg);
  666. }
  667. CheckField.prototype.make_input = function() { var me = this;
  668. this.input = $a_input(this.input_area,'checkbox');
  669. $y(this.input, {width:"16px", border:'0px', margin:'2px'}); // no specs for checkbox
  670. this.input.onchange = function() {
  671. me.set(this.checked?1:0);
  672. me.run_trigger();
  673. }
  674. if(isIE){
  675. this.input.onclick = this.input.onchange;
  676. $y(this.input, {margin:'-1px'});
  677. }
  678. this.input.set_input = function(v) {
  679. v = parseInt(v); if(isNaN(v)) v = 0;
  680. if(v) me.input.checked = true;
  681. else me.input.checked=false;
  682. }
  683. this.get_value= function() {
  684. return this.input.checked?1:0;
  685. }
  686. }
  687. CheckField.prototype.set_disp = function(val) {
  688. if (val){ $ds(this.checkimg); }
  689. else { $dh(this.checkimg); }
  690. }
  691. // ======================================================================================
  692. function TextField() { } TextField.prototype = new Field();
  693. TextField.prototype.set_disp = function(val) {
  694. this.disp_area.innerHTML = replace_newlines(val);
  695. }
  696. TextField.prototype.make_input = function() {
  697. var me = this;
  698. if(this.in_grid)
  699. return; // do nothing, text dialog will take over
  700. this.input = $a(this.input_area, 'textarea');
  701. this.input.wrap = 'off';
  702. if(this.df.fieldtype=='Small Text')
  703. this.input.style.height = "80px";
  704. this.input.set_input = function(v) {
  705. me.input.value = v;
  706. }
  707. this.input.onchange = function() {
  708. me.set(me.input.value);
  709. me.run_trigger();
  710. }
  711. this.get_value= function() {
  712. return this.input.value;
  713. }
  714. }
  715. // text dialog
  716. var text_dialog;
  717. function make_text_dialog() {
  718. var d = new Dialog(520,410,'Edit Text');
  719. d.make_body([
  720. ['Text', 'Enter Text'],
  721. ['HTML', 'Description'],
  722. ['Button', 'Update']
  723. ]);
  724. d.widgets['Update'].onclick = function() {
  725. var t = this.dialog;
  726. t.field.set(t.widgets['Enter Text'].value);
  727. t.hide();
  728. }
  729. d.onshow = function() {
  730. this.widgets['Enter Text'].style.height = '300px';
  731. var v = _f.get_value(this.field.doctype,this.field.docname,this.field.df.fieldname);
  732. this.widgets['Enter Text'].value = v==null?'':v;
  733. this.widgets['Enter Text'].focus();
  734. this.widgets['Description'].innerHTML = ''
  735. if(this.field.df.description)
  736. $a(this.widgets['Description'], 'div', 'field_description', '', this.field.df.description);
  737. }
  738. d.onhide = function() {
  739. if(_f.cur_grid_cell)
  740. _f.cur_grid_cell.grid.cell_deselect();
  741. }
  742. text_dialog = d;
  743. }
  744. TextField.prototype.table_refresh = function() {
  745. if(!this.text_dialog)
  746. make_text_dialog();
  747. text_dialog.set_title('Enter text for "'+ this.df.label +'"');
  748. text_dialog.field = this;
  749. text_dialog.show();
  750. }
  751. // Select
  752. // ======================================================================================
  753. function SelectField() { } SelectField.prototype = new Field();
  754. SelectField.prototype.make_input = function() {
  755. var me = this;
  756. var opt=[];
  757. if(this.in_filter && (!this.df.single_select)) {
  758. // multiple select
  759. this.input = $a(this.input_area, 'select');
  760. this.input.multiple = true;
  761. this.input.style.height = '4em';
  762. this.input.lab = $a(this.input_area, 'div', {fontSize:'9px',color:'#999'});
  763. this.input.lab.innerHTML = '(Use Ctrl+Click to select multiple or de-select)'
  764. } else {
  765. // Single select
  766. this.input = $a(this.input_area, 'select');
  767. this.input.onchange = function() {
  768. if(me.validate)
  769. me.validate();
  770. me.set(sel_val(this));
  771. // IE grid disappears
  772. if(isIE && me.in_grid) {
  773. $dh(_f.cur_grid_cell.grid.wrapper);
  774. $ds(_f.cur_grid_cell.grid.wrapper);
  775. }
  776. me.run_trigger();
  777. }
  778. }
  779. // set as single (to be called from report builder)
  780. this.set_as_single = function() {
  781. var i = this.input;
  782. i.multiple = false;
  783. i.style.height = null; // default
  784. if(i.lab)$dh(i.lab)
  785. }
  786. // refresh options list
  787. this.refresh_options = function(options) {
  788. if(options)
  789. me.df.options = options;
  790. me.options_list = me.df.options?me.df.options.split('\n'):[];
  791. // add options
  792. empty_select(this.input);
  793. if(me.in_filter && me.options_list[0]!='') {
  794. me.options_list = add_lists([''], me.options_list);
  795. }
  796. add_sel_options(this.input, me.options_list);
  797. }
  798. // refresh options
  799. this.onrefresh = function() {
  800. this.refresh_options();
  801. if(this.not_in_form) {
  802. this.input.value = '';
  803. return;
  804. }
  805. if(_f.get_value)
  806. var v = _f.get_value(this.doctype,this.docname,this.df.fieldname);
  807. else {
  808. if(this.options_list && this.options_list.length)
  809. var v = this.options_list[0];
  810. else
  811. var v = null;
  812. }
  813. this.input.set_input(v);
  814. }
  815. this.input.set_input=function(v) {
  816. if(!v) {
  817. if(!me.input.multiple) {
  818. if(me.docname) { // if called from onload without docname being set on fields
  819. if(me.options_list && me.options_list.length) {
  820. me.set(me.options_list[0]);
  821. me.input.value = me.options_list[0];
  822. } else {
  823. me.input.value = '';
  824. }
  825. }
  826. }
  827. } else {
  828. if(me.options_list && in_list(me.options_list, v)) {
  829. if(me.input.multiple) {
  830. for(var i=0; i<me.input.options.length; i++) {
  831. me.input.options[i].selected = 0;
  832. if(me.input.options[i].value && me.input.options[i].value == v)
  833. me.input.options[i].selected = 1;
  834. }
  835. } else {
  836. me.input.value = v;
  837. }
  838. }
  839. }
  840. }
  841. this.get_value= function() {
  842. if(me.input.multiple) {
  843. var l = [];
  844. for(var i=0;i<me.input.options.length; i++ ) {
  845. if(me.input.options[i].selected)l[l.length] = me.input.options[i].value;
  846. }
  847. return l;
  848. } else {
  849. if(me.input.options) {
  850. var val = sel_val(me.input);
  851. if(!val && !me.input.selectedIndex)
  852. val = me.input.options[0].value;
  853. return val;
  854. }
  855. return me.input.value;
  856. }
  857. }
  858. this.refresh();
  859. }
  860. // Time
  861. // ======================================================================================
  862. function TimeField() { } TimeField.prototype = new Field();
  863. TimeField.prototype.get_time = function() {
  864. return time_to_hhmm(sel_val(this.input_hr), sel_val(this.input_mn), sel_val(this.input_am));
  865. }
  866. TimeField.prototype.set_time = function(v) {
  867. //show_alert(ret);
  868. ret = time_to_ampm(v);
  869. this.input_hr.inp.value = ret[0];
  870. this.input_mn.inp.value = ret[1];
  871. this.input_am.inp.value = ret[2];
  872. }
  873. TimeField.prototype.set_style_mandatory = function() { }
  874. TimeField.prototype.set_as_error = function() { }
  875. TimeField.prototype.make_input = function() { var me = this;
  876. this.input = $a(this.input_area, 'div', 'time_field');
  877. var t = make_table(this.input, 1, 3, '160px');
  878. var opt_hr = ['1','2','3','4','5','6','7','8','9','10','11','12'];
  879. var opt_mn = ['00','05','10','15','20','25','30','35','40','45','50','55'];
  880. var opt_am = ['AM','PM'];
  881. this.input_hr = new SelectWidget($td(t,0,0), opt_hr, '40px');
  882. this.input_mn = new SelectWidget($td(t,0,1), opt_mn, '40px');
  883. this.input_am = new SelectWidget($td(t,0,2), opt_am, '40px');
  884. this.input_hr.inp.isactive = 1; this.input_mn.inp.isactive = 1; this.input_am.inp.isactive = 1;
  885. if(this.input_hr.btn) {
  886. this.input_hr.btn.isactive = 1; this.input_mn.btn.isactive = 1; this.input_am.btn.isactive = 1;
  887. }
  888. var onchange_fn = function() {
  889. me.set(me.get_time());
  890. me.run_trigger();
  891. }
  892. this.input_hr.inp.onchange = onchange_fn;
  893. this.input_mn.inp.onchange = onchange_fn;
  894. this.input_am.inp.onchange = onchange_fn;
  895. this.onrefresh = function() {
  896. var v = _f.get_value ? _f.get_value(me.doctype,me.docname,me.df.fieldname) : null;
  897. me.set_time(v);
  898. if(!v)
  899. me.set(me.get_time());
  900. }
  901. this.input.set_input=function(v) {
  902. if(v==null)v='';
  903. me.set_time(v);
  904. }
  905. this.get_value = function() {
  906. return this.get_time();
  907. }
  908. this.refresh();
  909. }
  910. TimeField.prototype.set_disp=function(v) {
  911. var t = time_to_ampm(v);
  912. var t = t[0]+':'+t[1]+' '+t[2];
  913. this.set_disp_html(t);
  914. }
  915. // ======================================================================================
  916. // Used by date and link fields
  917. function makeinput_popup(me, iconsrc, iconsrc1, iconsrc2) {
  918. me.input = $a(me.input_area, 'div');
  919. if(!me.not_in_form)
  920. $y(me.input, {width:'80%'});
  921. me.input.set_width = function(w) {
  922. $y(me.input, {width:(w-2)+'px'});
  923. }
  924. var tab = $a(me.input, 'table');
  925. me.tab = tab;
  926. $y(tab, {width:'100%', borderCollapse:'collapse', tableLayout:'fixed'});
  927. var c0 = tab.insertRow(0).insertCell(0);
  928. var c1 = tab.rows[0].insertCell(1);
  929. $y(c1,{width: '20px'});
  930. me.txt = $a($a($a(c0, 'div', '', {paddingRight:'8px'}), 'div'), 'input', '', {width:'100%'});
  931. me.btn = $a(c1, 'div', 'wn-icon ' + iconsrc, {width:'16px'});
  932. if(iconsrc1) // link
  933. me.btn.setAttribute('title','Search');
  934. else // date
  935. me.btn.setAttribute('title','Select Date');
  936. if(iconsrc1) {
  937. var c2 = tab.rows[0].insertCell(2);
  938. $y(c2,{width: '20px'});
  939. me.btn1 = $a(c2, 'div', 'wn-icon ' + iconsrc1, {width:'16px'});
  940. me.btn1.setAttribute('title','Open Link');
  941. }
  942. if(iconsrc2) {
  943. var c3 = tab.rows[0].insertCell(3);
  944. $y(c3,{width: '20px'});
  945. me.btn2 = $a(c3, 'div', 'wn-icon ' + iconsrc2, {width:'16px'});
  946. me.btn2.setAttribute('title','Create New');
  947. $dh(me.btn2);
  948. }
  949. if(me.df.colour)
  950. me.txt.style.background = '#'+me.df.colour.split(':')[1];
  951. me.txt.name = me.df.fieldname;
  952. me.setdisabled = function(tf) { me.txt.disabled = tf; }
  953. }
  954. var tmpid = 0;
  955. // ======================================================================================
  956. function make_field(docfield, doctype, parent, frm, in_grid, hide_label) { // Factory
  957. switch(docfield.fieldtype.toLowerCase()) {
  958. // general fields
  959. case 'data':var f = new DataField(); break;
  960. case 'password':var f = new DataField(); break;
  961. case 'int':var f = new IntField(); break;
  962. case 'float':var f = new FloatField(); break;
  963. case 'currency':var f = new CurrencyField(); break;
  964. case 'read only':var f = new ReadOnlyField(); break;
  965. case 'link':var f = new LinkField(); break;
  966. case 'date':var f = new DateField(); break;
  967. case 'time':var f = new TimeField(); break;
  968. case 'html':var f = new HTMLField(); break;
  969. case 'check':var f = new CheckField(); break;
  970. case 'text':var f = new TextField(); break;
  971. case 'small text':var f = new TextField(); break;
  972. case 'select':var f = new SelectField(); break;
  973. // form fields
  974. case 'code':var f = new _f.CodeField(); break;
  975. case 'text editor':var f = new _f.CodeField(); break;
  976. case 'button':var f = new _f.ButtonField(); break;
  977. case 'table':var f = new _f.TableField(); break;
  978. case 'section break':var f= new _f.SectionBreak(); break;
  979. case 'column break':var f= new _f.ColumnBreak(); break;
  980. case 'image':var f= new _f.ImageField(); break;
  981. }
  982. f.parent = parent;
  983. f.doctype = doctype;
  984. f.df = docfield;
  985. f.perm = frm ? frm.perm : [[1,1,1]];
  986. if(_f)
  987. f.col_break_width = _f.cur_col_break_width;
  988. if(in_grid) {
  989. f.in_grid = true;
  990. f.with_label = 0;
  991. }
  992. if(hide_label) {
  993. f.with_label = 0;
  994. }
  995. if(frm) {
  996. f.frm = frm;
  997. if(parent)
  998. f.layout_cell = parent.parentNode;
  999. }
  1000. if(f.init) f.init();
  1001. f.make_body();
  1002. return f;
  1003. }