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

13 年之前
13 年之前
13 年之前
13 年之前
12 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
13 年之前
12 年之前
12 年之前
12 年之前
12 年之前
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  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. // fields.js
  23. //
  24. // Fields are divided into 2 types
  25. // 1. Standard fields are loaded with the libarary
  26. // 2. Special fields are loaded with form.compressed.js
  27. //
  28. //
  29. // + wrapper
  30. // + input_area
  31. // + display_area
  32. // ======================================================================================
  33. var no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image'];
  34. var codeid=0; var code_editors={};
  35. function Field() {
  36. this.with_label = 1;
  37. }
  38. Field.prototype.make_body = function() {
  39. var ischk = (this.df.fieldtype=='Check' ? 1 : 0);
  40. // parent element
  41. if(this.parent)
  42. this.wrapper = $a(this.parent, (this.with_label || this.df.fieldtype=="HTML" ? 'div' : 'span'));
  43. else
  44. this.wrapper = document.createElement((this.with_label || this.df.fieldtype=="HTML" ? 'div' : 'span'));
  45. $(this.wrapper).addClass("field-wrapper");
  46. this.label_area = $a(this.wrapper, 'div', '',
  47. {margin:'0px 0px 2px 0px', minHeight:'1em'});
  48. var label_wrapper = this.label_area;
  49. if(ischk && !this.in_grid) {
  50. var label_wrapper = $("<div style='margin-bottom: 9px'>").appendTo(this.label_area).get(0);
  51. this.input_area = $a(label_wrapper, 'span', '', {marginRight:'4px'});
  52. this.disp_area = $a(label_wrapper, 'span', '', {marginRight:'4px'});
  53. }
  54. // label
  55. if(this.with_label) {
  56. this.label_span = $a(label_wrapper, 'span', 'small')
  57. if(wn.boot && wn.boot.developer_mode)
  58. $(this.label_span).attr("title", this.df.fieldname);
  59. // error icon
  60. this.label_icon = $('<i class="icon icon-warning-sign">').toggle(false)
  61. .appendTo(label_wrapper).css('margin-left','7px')
  62. .attr("title", "This field is mandatory.");
  63. } else {
  64. this.label_span = $a(label_wrapper, 'span', '', {marginRight:'4px'})
  65. $dh(label_wrapper);
  66. }
  67. // make the input areas
  68. if(!this.input_area) {
  69. this.input_area = $a(this.wrapper, (this.with_label ? 'div' : 'span'));
  70. this.disp_area = $a(this.wrapper, (this.with_label ? 'div' : 'span'));
  71. }
  72. // apply style
  73. if(this.in_grid) {
  74. if(this.label_area) $dh(this.label_area);
  75. } else {
  76. this.input_area.className = 'input_area';
  77. $y(this.wrapper,{marginBottom:'9px'});
  78. // set description
  79. this.set_description();
  80. }
  81. // bind label refresh
  82. if(this.onmake)this.onmake();
  83. }
  84. Field.prototype.set_max_width = function() {
  85. var no_max = ['Code', 'Text Editor', 'Text', 'Small Text', 'Table', 'HTML']
  86. if(this.wrapper && this.layout_cell && this.layout_cell.parentNode.cells
  87. && this.layout_cell.parentNode.cells.length==1 && !in_list(no_max, this.df.fieldtype)) {
  88. $y(this.wrapper, {paddingRight:'50%'});
  89. }
  90. }
  91. Field.prototype.set_label = function(label) {
  92. if(!label) label = this.df.label;
  93. if(this.with_label && this.label_area && this.label!=label) {
  94. this.label_span.innerHTML = wn._(label);
  95. // always store this.label as this.df.label, so that custom label does not change back
  96. this.label = this.df.label;
  97. }
  98. }
  99. Field.prototype.set_description = function(txt) {
  100. if(this.df.description || txt) {
  101. // parent
  102. if(!this.desc_area) {
  103. var p = in_list(['Text Editor', 'Code', 'Check'], this.df.fieldtype)
  104. ? this.label_area : this.wrapper;
  105. this.desc_area = $a(p, 'div', 'help small');
  106. }
  107. $(this.desc_area).html(wn._(this.df.description || txt));
  108. }
  109. }
  110. Field.prototype.get_status = function() {
  111. // if used in filters
  112. if(this.in_filter)
  113. this.not_in_form = this.in_filter;
  114. if(this.not_in_form) {
  115. return 'Write';
  116. }
  117. if(!this.df.permlevel) this.df.permlevel = 0;
  118. var p = this.perm[this.df.permlevel];
  119. var ret;
  120. // permission level
  121. if(p && p[WRITE] && !this.df.disabled)
  122. ret='Write';
  123. else if(p && p[READ])
  124. ret='Read';
  125. else
  126. ret='None';
  127. // hidden
  128. if(cint(this.df.hidden)) {
  129. ret = 'None';
  130. }
  131. // for submit
  132. if(ret=='Write' && cint(cur_frm.doc.docstatus) > 0) {
  133. ret = 'Read';
  134. }
  135. // allow on submit
  136. var a_o_s = cint(this.df.allow_on_submit);
  137. if(a_o_s && (this.in_grid || (this.frm && this.frm.meta.istable))) {
  138. // if grid is allow-on-submit, everything in it is too!
  139. a_o_s = null;
  140. if(this.in_grid)
  141. a_o_s = this.grid.field.df.allow_on_submit;
  142. if(this.frm.meta.istable) {
  143. a_o_s = _f.cur_grid.field.df.allow_on_submit;
  144. }
  145. }
  146. if(ret=="Read" && a_o_s && cint(cur_frm.doc.docstatus)==1 &&
  147. cur_frm.perm[this.df.permlevel][WRITE]) {
  148. ret='Write';
  149. }
  150. // workflow state
  151. if(ret=="Write" && cur_frm && cur_frm.state_fieldname) {
  152. if(cint(cur_frm.read_only)) {
  153. ret = 'Read';
  154. }
  155. // fields updated by workflow must be read-only
  156. if(in_list(cur_frm.states.update_fields, this.df.fieldname) ||
  157. this.df.fieldname==cur_frm.state_fieldname) {
  158. ret = 'Read';
  159. }
  160. }
  161. // make a field read_only if read_only
  162. // is checked (disregards write permission)
  163. if(ret=="Write" && cint(this.df.read_only)) {
  164. ret = "Read";
  165. }
  166. return ret;
  167. }
  168. Field.prototype.set_style_mandatory = function(add) {
  169. if(add) {
  170. $(this.txt ? this.txt : this.input).addClass('input-mandatory');
  171. if(this.disp_area) $(this.disp_area).addClass('input-mandatory');
  172. } else {
  173. $(this.txt ? this.txt : this.input).removeClass('input-mandatory');
  174. if(this.disp_area) $(this.disp_area).removeClass('input-mandatory');
  175. }
  176. }
  177. Field.prototype.refresh_mandatory = function() {
  178. if(this.in_filter)return;
  179. // mandatory changes
  180. if(this.df.reqd) {
  181. if(this.label_area) this.label_area.style.color= "#d22";
  182. this.set_style_mandatory(1);
  183. } else {
  184. if(this.label_area) this.label_area.style.color= "#222";
  185. this.set_style_mandatory(0);
  186. }
  187. this.refresh_label_icon()
  188. this.set_reqd = this.df.reqd;
  189. }
  190. Field.prototype.refresh_display = function() {
  191. // from permission
  192. if(!this.current_status || this.current_status!=this.disp_status) { // status changed
  193. if(this.disp_status=='Write') { // write
  194. if(this.make_input&&(!this.input)) { // make input if reqd
  195. this.make_input();
  196. if(this.txt || this.input)
  197. $(this.txt || this.input).addClass("mousetrap");
  198. if(this.onmake_input) this.onmake_input();
  199. }
  200. if(this.show) this.show()
  201. else { $ds(this.wrapper); }
  202. // input or content
  203. if(this.input) { // if there, show it!
  204. $ds(this.input_area);
  205. $dh(this.disp_area);
  206. if(this.input.refresh)
  207. this.input.refresh();
  208. } else { // no widget
  209. $dh(this.input_area);
  210. $ds(this.disp_area);
  211. }
  212. } else if(this.disp_status=='Read') {
  213. // read
  214. if(this.show) this.show()
  215. else { $ds(this.wrapper); }
  216. $dh(this.input_area);
  217. $ds(this.disp_area);
  218. } else {
  219. // None - hide all
  220. if(this.hide) this.hide();
  221. else $dh(this.wrapper);
  222. }
  223. this.current_status = this.disp_status;
  224. }
  225. }
  226. Field.prototype.refresh = function() {
  227. // get status
  228. this.disp_status = this.get_status();
  229. // if there is a special refresh in case of table, then this is not valid
  230. if(this.in_grid
  231. && this.table_refresh
  232. && this.disp_status == 'Write')
  233. { this.table_refresh(); return; }
  234. this.set_label();
  235. this.refresh_display();
  236. if(this.input) {
  237. if(this.input.refresh) this.input.refresh(this.df);
  238. }
  239. // further refresh
  240. if(this.onrefresh)
  241. this.onrefresh(); // called by various fields
  242. if(this.wrapper) {
  243. this.wrapper.fieldobj = this;
  244. $(this.wrapper).trigger('refresh');
  245. }
  246. if(!this.not_in_form)
  247. this.set_input(_f.get_value(this.doctype,this.docname,this.df.fieldname));
  248. this.refresh_mandatory();
  249. this.set_max_width();
  250. }
  251. Field.prototype.refresh_label_icon = function() {
  252. // mandatory
  253. var to_update = false;
  254. if(this.df.reqd && this.get_value && is_null(this.get_value()))
  255. to_update = true;
  256. if(!to_update && this.df.has_error) this.df.has_error = false;
  257. if(this.label_icon) this.label_icon.css("display", (to_update ? "inline-block" : "none"));
  258. $(this.txt ? this.txt : this.input).toggleClass('field-to-update', to_update);
  259. $(this.txt ? this.txt : this.input).toggleClass('field-has-error',
  260. this.df.has_error ? true : false);
  261. }
  262. Field.prototype.set = function(val) {
  263. // not in form
  264. if(this.not_in_form)
  265. return;
  266. if((!this.docname) && this.grid) {
  267. this.docname = this.grid.add_newrow(); // new row
  268. }
  269. if(this.validate)
  270. val = this.validate(val);
  271. cur_frm.set_value_in_locals(this.doctype, this.docname,
  272. this.df.fieldname, val);
  273. this.value = val; // for return
  274. }
  275. Field.prototype.set_input = function(val) {
  276. this.value = val;
  277. if(this.input && this.input.set_input) {
  278. this.input.set_input(val); // in widget
  279. }
  280. var disp_val = val;
  281. if(val==null)
  282. disp_val = '';
  283. this.set_disp(disp_val); // text
  284. }
  285. Field.prototype.run_trigger = function() {
  286. // update mandatory icon
  287. this.refresh_label_icon();
  288. if(this.not_in_form) {
  289. return;
  290. }
  291. if(cur_frm.cscript[this.df.fieldname])
  292. cur_frm.runclientscript(this.df.fieldname, this.doctype, this.docname);
  293. cur_frm.refresh_dependency();
  294. }
  295. Field.prototype.set_disp_html = function(t) {
  296. if(this.disp_area){
  297. $(this.disp_area).addClass('disp_area');
  298. this.disp_area.innerHTML = (t==null ? '' : t);
  299. if(!t) $(this.disp_area).addClass('disp_area_no_val');
  300. }
  301. }
  302. Field.prototype.set_disp = function(val) {
  303. this.set_disp_html(val);
  304. }
  305. Field.prototype.get_input = function() {
  306. return this.txt || this.input;
  307. }
  308. // for grids (activate against a particular record in the table
  309. Field.prototype.activate = function(docname) {
  310. this.docname = docname;
  311. this.refresh();
  312. if(this.input) {
  313. var v = _f.get_value(this.doctype, this.docname, this.df.fieldname);
  314. this.last_value=v;
  315. // set input value
  316. if(this.input.onchange && this.input.get_value && this.input.get_value() !=v) {
  317. if(this.validate)
  318. this.input.set_value(this.validate(v));
  319. else
  320. this.input.set_value((v==null)?'':v);
  321. if(this.format_input)
  322. this.format_input();
  323. }
  324. if(this.input.focus){
  325. try{this.input.focus();} catch(e){} // IE Fix - Unexpected call???
  326. }
  327. }
  328. if(this.txt) {
  329. try{this.txt.focus();} catch(e){} // IE Fix - Unexpected call???
  330. this.txt.field_object = this;
  331. }
  332. }
  333. function DataField() { } DataField.prototype = new Field();
  334. DataField.prototype.make_input = function() {
  335. var me = this;
  336. this.input = $a_input(this.input_area, this.df.fieldtype=='Password' ? 'password' : 'text');
  337. this.get_value= function() {
  338. var v = this.input.value;
  339. if(this.validate)
  340. v = this.validate(v);
  341. return v;
  342. }
  343. this.input.name = this.df.fieldname;
  344. $(this.input).blur(function() {
  345. me.set_value(me.get_value ? me.get_value() : $(this.input).val());
  346. });
  347. this.set_value = function(val) {
  348. if(!me.last_value)me.last_value='';
  349. if(me.validate) {
  350. val = me.validate(val);
  351. me.input.value = val==undefined ? '' : val;
  352. }
  353. me.set(val);
  354. if(me.format_input)
  355. me.format_input();
  356. if(in_list(['Currency','Float','Int'], me.df.fieldtype)) {
  357. if(flt(me.last_value)==flt(val)) {
  358. me.last_value = val;
  359. return; // do not run trigger
  360. }
  361. }
  362. me.last_value = val;
  363. me.run_trigger();
  364. }
  365. this.input.set_input = function(val) {
  366. if(val==null)val='';
  367. me.input.value = val;
  368. if(me.format_input)me.format_input();
  369. }
  370. }
  371. DataField.prototype.validate = function(v) {
  372. if(this.df.options == 'Phone') {
  373. if(v+''=='')return '';
  374. v1 = ''
  375. // phone may start with + and must only have numbers later, '-' and ' ' are stripped
  376. v = v.replace(/ /g, '').replace(/-/g, '').replace(/\(/g, '').replace(/\)/g, '');
  377. // allow initial +,0,00
  378. if(v && v.substr(0,1)=='+') {
  379. v1 = '+'; v = v.substr(1);
  380. }
  381. if(v && v.substr(0,2)=='00') {
  382. v1 += '00'; v = v.substr(2);
  383. }
  384. if(v && v.substr(0,1)=='0') {
  385. v1 += '0'; v = v.substr(1);
  386. }
  387. v1 += cint(v) + '';
  388. return v1;
  389. } else if(this.df.options == 'Email') {
  390. if(v+''=='')return '';
  391. if(!validate_email(v)) {
  392. msgprint(this.df.label + ': ' + v + ' is not a valid email id');
  393. return '';
  394. } else
  395. return v;
  396. } else {
  397. return v;
  398. }
  399. }
  400. // ======================================================================================
  401. function ReadOnlyField() { }
  402. ReadOnlyField.prototype = new Field();
  403. // ======================================================================================
  404. function HTMLField() { }
  405. HTMLField.prototype = new Field();
  406. HTMLField.prototype.with_label = 0;
  407. HTMLField.prototype.set_disp = function(val) { if(this.disp_area) this.disp_area.innerHTML = val; }
  408. HTMLField.prototype.set_input = function(val) { if(val) this.set_disp(val); }
  409. HTMLField.prototype.onrefresh = function() { if(this.df.options) this.set_disp(this.df.options); }
  410. // ======================================================================================
  411. var datepicker_active = 0;
  412. function get_datepicker_options() {
  413. var datepicker_options = {
  414. dateFormat: (sys_defaults.date_format || 'yy-mm-dd').replace('yyyy','yy'),
  415. altFormat:'yy-mm-dd',
  416. changeYear: true,
  417. yearRange: "-70Y:+10Y",
  418. beforeShow: function(input, inst) {
  419. datepicker_active = 1
  420. },
  421. onClose: function(dateText, inst) {
  422. datepicker_active = 0;
  423. if(_f.cur_grid_cell)
  424. _f.cur_grid_cell.grid.cell_deselect();
  425. },
  426. }
  427. return datepicker_options;
  428. }
  429. function DateField() { } DateField.prototype = new Field();
  430. DateField.prototype.make_input = function() {
  431. var me = this;
  432. this.input = $("<input type='text' data-fieldtype='Date'>")
  433. .appendTo(this.input_area).get(0);
  434. $(this.input).datepicker(get_datepicker_options());
  435. this.setup_input();
  436. }
  437. DateField.prototype.setup_input = function() {
  438. var me = this;
  439. me.input.onchange = function() {
  440. // input as dd-mm-yyyy
  441. if(this.value==null)this.value='';
  442. if(!this.not_in_form)
  443. me.set(dateutil.user_to_str(me.input.value));
  444. me.run_trigger();
  445. }
  446. me.input.set_input = function(val) {
  447. if(val==null)val='';
  448. else val=dateutil.str_to_user(val);
  449. me.input.value = val;
  450. }
  451. me.get_value = function() {
  452. if(me.input.value)
  453. return dateutil.user_to_str(me.input.value);
  454. }
  455. }
  456. DateField.prototype.set_disp = function(val) {
  457. var v = dateutil.str_to_user(val);
  458. if(v==null)v = '';
  459. this.set_disp_html(v);
  460. }
  461. DateField.prototype.validate = function(v) {
  462. var v = wn.datetime.validate(v);
  463. if(!v) {
  464. msgprint (wn._("Date must be in format") + ": " + (sys_defaults.date_format || "yyyy-mm-dd"));
  465. this.input.set_input('');
  466. return '';
  467. }
  468. return v;
  469. };
  470. // reference when a new record is created via link
  471. function LinkField() { } LinkField.prototype = new Field();
  472. LinkField.prototype.make_input = function() {
  473. var me = this;
  474. if(me.df.no_buttons) {
  475. this.txt = $("<input type='text'>")
  476. .appendTo(this.input_area).get(0);
  477. this.input = this.txt;
  478. } else {
  479. me.input = me.input_area;
  480. $(me.input_area).addClass("input-append link-field");
  481. me.txt = $('<input type="text" style="margin-right: 0px;">')
  482. .css({"width": me.in_filter ? "100px" : (me.in_grid ? "35%" : "60%")})
  483. .appendTo(me.input_area).get(0);
  484. me.btn = $('<button class="btn" title="'+wn._('Search Link')+'">\
  485. <i class="icon-search"></i></button>').appendTo(me.input_area).get(0);
  486. me.btn1 = $('<button class="btn" title="'+wn._('Open Link')+'">\
  487. <i class="icon-play"></i></button>').appendTo(me.input_area).get(0);
  488. me.btn2 = $('<button class="btn" title="'+wn._('Make New')+'">\
  489. <i class="icon-plus"></i></button>').appendTo(me.input_area).get(0);
  490. me.txt.name = me.df.fieldname;
  491. me.setdisabled = function(tf) { me.txt.disabled = tf; }
  492. // setup buttons
  493. me.setup_buttons();
  494. }
  495. me.onrefresh = function() {
  496. var can_create = in_list(wn.boot.profile.can_create, me.df.options);
  497. var can_read = in_list(wn.boot.profile.can_read, me.df.options);
  498. if(!can_create) $(this.btn2).remove();
  499. if(!can_read) $(this.btn1).remove();
  500. }
  501. me.onrefresh();
  502. me.txt.field_object = this;
  503. // set onchange triggers
  504. me.input.set_input = function(val) {
  505. if(val==undefined)val='';
  506. me.txt.value = val;
  507. }
  508. me.get_value = function() { return me.txt.value; }
  509. $(me.txt).autocomplete({
  510. source: function(request, response) {
  511. wn.call({
  512. method:'webnotes.widgets.search.search_link',
  513. args: {
  514. 'txt': request.term,
  515. 'dt': me.df.options,
  516. 'query': me.get_custom_query()
  517. },
  518. callback: function(r) {
  519. response(r.results);
  520. },
  521. });
  522. },
  523. select: function(event, ui) {
  524. me.set_input_value(ui.item.value);
  525. }
  526. }).data('autocomplete')._renderItem = function(ul, item) {
  527. return $('<li></li>')
  528. .data('item.autocomplete', item)
  529. .append(repl('<a><span style="font-weight: bold;">%(label)s</span><br>\
  530. <span style="font-size:10px;">%(info)s</span></a>',
  531. item))
  532. .appendTo(ul);
  533. };
  534. $(this.txt).change(function() {
  535. var val = $(this).val();//me.get_value();
  536. me.set_input_value_executed = false;
  537. if(!val) {
  538. if(selector && selector.display)
  539. return;
  540. me.set_input_value('');
  541. } else {
  542. // SetTimeout hack! if in put is set via autocomplete, do not validate twice
  543. setTimeout(function() {
  544. if (!me.set_input_value_executed) {
  545. me.set_input_value(val);
  546. }
  547. }, 1000);
  548. }
  549. })
  550. }
  551. LinkField.prototype.get_custom_query = function() {
  552. this.set_get_query();
  553. if(this.get_query) {
  554. if(cur_frm)
  555. var doc = locals[cur_frm.doctype][cur_frm.docname];
  556. return this.get_query(doc, this.doctype, this.docname);
  557. }
  558. }
  559. LinkField.prototype.setup_buttons = function() {
  560. var me = this;
  561. // magnifier - search
  562. me.btn.onclick = function() {
  563. selector.set(me, me.df.options, me.df.label);
  564. selector.show(me.txt);
  565. }
  566. // open
  567. if(me.btn1)me.btn1.onclick = function() {
  568. if(me.txt.value && me.df.options) { loaddoc(me.df.options, me.txt.value); }
  569. }
  570. // add button - for inline creation of records
  571. me.can_create = 0;
  572. if((!me.not_in_form) && in_list(profile.can_create, me.df.options)) {
  573. me.can_create = 1;
  574. me.btn2.onclick = function() {
  575. var on_save_callback = function(new_rec) {
  576. if(new_rec) {
  577. var d = _f.calling_doc_stack.pop(); // patch for composites
  578. locals[d[0]][d[1]][me.df.fieldname] = new_rec;
  579. me.refresh();
  580. if(me.grid)me.grid.refresh();
  581. // call script
  582. me.run_trigger();
  583. }
  584. }
  585. _f.calling_doc_stack.push([me.doctype, me.docname]);
  586. new_doc(me.df.options);
  587. }
  588. } else {
  589. $(me.btn2).remove();
  590. }
  591. }
  592. LinkField.prototype.set_input_value = function(val) {
  593. var me = this;
  594. // SetTimeout hack! if in put is set via autocomplete, do not validate twice
  595. me.set_input_value_executed = true;
  596. var from_selector = false;
  597. if(selector && selector.display) from_selector = true;
  598. // refresh mandatory style
  599. me.refresh_label_icon();
  600. // not in form, do nothing
  601. if(me.not_in_form) {
  602. $(this.txt).val(val);
  603. return;
  604. }
  605. // same value, do nothing
  606. if(cur_frm) {
  607. if(val == locals[me.doctype][me.docname][me.df.fieldname]) {
  608. //me.set(val); // one more time, grid bug?
  609. me.run_trigger(); // wanted - called as refresh?
  610. return;
  611. }
  612. }
  613. // set in locals
  614. me.set(val);
  615. // deselect cell if in grid
  616. if(_f.cur_grid_cell)
  617. _f.cur_grid_cell.grid.cell_deselect();
  618. if(val) {
  619. // validate only if val is not empty
  620. me.validate_link(val, from_selector);
  621. } else {
  622. // run trigger if value is cleared
  623. me.run_trigger();
  624. }
  625. }
  626. LinkField.prototype.validate_link = function(val, from_selector) {
  627. // validate the value just entered
  628. var me = this;
  629. if(this.df.options=="[Select]") {
  630. $(me.txt).val(val);
  631. me.run_trigger();
  632. return;
  633. }
  634. var fetch = '';
  635. if(cur_frm.fetch_dict[me.df.fieldname])
  636. fetch = cur_frm.fetch_dict[me.df.fieldname].columns.join(', ');
  637. $c('webnotes.widgets.form.utils.validate_link', {
  638. 'value':val,
  639. 'options':me.df.options,
  640. 'fetch': fetch
  641. },
  642. function(r,rt) {
  643. if(r.message=='Ok') {
  644. // set fetch values
  645. if($(me.txt).val()!=val) {
  646. if((me.grid && !from_selector) || (!me.grid)) {
  647. $(me.txt).val(val);
  648. }
  649. }
  650. if(r.fetch_values)
  651. me.set_fetch_values(r.fetch_values);
  652. me.run_trigger();
  653. } else {
  654. me.txt.value = '';
  655. me.set('');
  656. }
  657. }
  658. );
  659. }
  660. LinkField.prototype.set_fetch_values = function(fetch_values) {
  661. var fl = cur_frm.fetch_dict[this.df.fieldname].fields;
  662. var changed_fields = [];
  663. for(var i=0; i< fl.length; i++) {
  664. if(locals[this.doctype][this.docname][fl[i]]!=fetch_values[i]) {
  665. locals[this.doctype][this.docname][fl[i]] = fetch_values[i];
  666. if(!this.grid) {
  667. refresh_field(fl[i]);
  668. // call trigger on the target field
  669. changed_fields.push(fl[i]);
  670. }
  671. }
  672. }
  673. // run triggers
  674. for(i=0; i<changed_fields.length; i++) {
  675. if(cur_frm.fields_dict[changed_fields[i]]) // on main
  676. cur_frm.fields_dict[changed_fields[i]].run_trigger();
  677. }
  678. // refresh grid
  679. if(this.grid) this.grid.refresh();
  680. }
  681. LinkField.prototype.set_get_query = function() {
  682. if(this.get_query)return;
  683. if(this.grid) {
  684. var f = this.grid.get_field(this.df.fieldname);
  685. if(f.get_query) this.get_query = f.get_query;
  686. }
  687. }
  688. LinkField.prototype.set_disp = function(val) {
  689. var t = null;
  690. if(val)t = "<a href=\'javascript:loaddoc(\""+this.df.options+"\", \""+val+"\")\'>"+val+"</a>";
  691. this.set_disp_html(t);
  692. }
  693. // ======================================================================================
  694. function IntField() { } IntField.prototype = new DataField();
  695. IntField.prototype.validate = function(v) {
  696. if(isNaN(parseInt(v)))return null;
  697. return cint(v);
  698. };
  699. IntField.prototype.format_input = function() {
  700. if(this.input.value==null) this.input.value='';
  701. }
  702. // ======================================================================================
  703. function FloatField() { } FloatField.prototype = new DataField();
  704. FloatField.prototype.validate = function(v) {
  705. var v= parseFloat(v);
  706. if(isNaN(v))
  707. return null;
  708. return v;
  709. };
  710. FloatField.prototype.format_input = function() {
  711. if(this.input.value==null) this.input.value='';
  712. }
  713. FloatField.prototype.onmake_input = function() {
  714. if(!this.input) return;
  715. this.input.onfocus = function() {
  716. this.select();
  717. }
  718. }
  719. FloatField.prototype.set_disp = function(val) {
  720. this.set_disp_html(wn.format(val, this.df, null, locals[this.doctype][this.name]));
  721. }
  722. function PercentField() { } PercentField.prototype = new FloatField();
  723. PercentField.prototype.set_disp = function(val) {
  724. this.set_disp_html(wn.format(val, this.df));
  725. }
  726. function CurrencyField() { } CurrencyField.prototype = new FloatField();
  727. CurrencyField.prototype.validate = function(v) {
  728. if(v==null || v=='')
  729. return 0;
  730. return flt(v);
  731. }
  732. CurrencyField.prototype.get_formatted = function(val) {
  733. if(this.not_in_form)
  734. return val;
  735. var doc = null;
  736. if(this.doctype && this.docname && locals[this.doctype])
  737. doc = locals[this.doctype][this.docname];
  738. return get_currency_symbol(wn.meta.get_field_currency(this.df, doc))
  739. + " " + format_number(val);
  740. }
  741. CurrencyField.prototype.set_disp = function(val) {
  742. this.set_disp_html(this.get_formatted(val));
  743. }
  744. function CheckField() { } CheckField.prototype = new Field();
  745. CheckField.prototype.validate = function(v) {
  746. return cint(v);
  747. };
  748. CheckField.prototype.onmake = function() {
  749. this.checkimg = $("<i class='icon-check'></i>").appendTo(this.disp_area);
  750. }
  751. CheckField.prototype.make_input = function() { var me = this;
  752. this.input = $("<input type='checkbox'>")
  753. .appendTo(this.input_area)
  754. .css({"border":"0px", "margin-top":"-2px", "width": "16px"}).get(0);
  755. $(this.input).change(function() {
  756. me.set(this.checked ? 1 : 0);
  757. me.run_trigger();
  758. })
  759. this.input.set_input = function(v) {
  760. me.input.checked = cint(v) ? true : false;
  761. }
  762. this.get_value= function() {
  763. return this.input.checked ? 1 : 0;
  764. }
  765. }
  766. CheckField.prototype.set_disp = function(val) {
  767. this.checkimg.toggle(val);
  768. }
  769. function TextField() { } TextField.prototype = new Field();
  770. TextField.prototype.set_disp = function(val) {
  771. this.disp_area.innerHTML = replace_newlines(val);
  772. }
  773. TextField.prototype.make_input = function() {
  774. var me = this;
  775. if(this.in_grid)
  776. return; // do nothing, text dialog will take over
  777. this.input = $a(this.input_area, 'textarea');
  778. if(this.df.fieldtype=='Small Text') {
  779. $(this.input).css({height: "80px"});
  780. } else if(this.df.width) {
  781. $(this.input).css({height: cint(this.df.width) + "px"});
  782. } else {
  783. $(this.input).css({height: "160px"});
  784. }
  785. this.input.set_input = function(v) {
  786. me.input.value = (v==null ? "" : v);
  787. }
  788. this.input.onchange = function() {
  789. me.set(me.input.value);
  790. me.run_trigger();
  791. }
  792. this.get_value= function() {
  793. return this.input.value;
  794. }
  795. }
  796. // text dialog
  797. var text_dialog;
  798. function make_text_dialog() {
  799. var d = new Dialog(520,410,'Edit Text');
  800. d.make_body([
  801. ['Text', 'Enter Text'],
  802. ['HTML', 'Description'],
  803. ['Button', 'Update']
  804. ]);
  805. d.widgets['Update'].onclick = function() {
  806. var t = this.dialog;
  807. t.field.set(t.widgets['Enter Text'].value);
  808. t.hide();
  809. }
  810. d.onshow = function() {
  811. this.widgets['Enter Text'].style.height = '300px';
  812. var v = _f.get_value(this.field.doctype,this.field.docname,this.field.df.fieldname);
  813. this.widgets['Enter Text'].value = v==null?'':v;
  814. this.widgets['Enter Text'].focus();
  815. this.widgets['Description'].innerHTML = ''
  816. if(this.field.df.description)
  817. $a(this.widgets['Description'], 'div', 'help small', '', this.field.df.description);
  818. }
  819. d.onhide = function() {
  820. if(_f.cur_grid_cell)
  821. _f.cur_grid_cell.grid.cell_deselect();
  822. }
  823. text_dialog = d;
  824. }
  825. TextField.prototype.table_refresh = function() {
  826. if(!this.text_dialog)
  827. make_text_dialog();
  828. text_dialog.set_title(wn._('Enter text for')+': "'+ wn._(this.df.label) +'"');
  829. text_dialog.field = this;
  830. text_dialog.show();
  831. }
  832. // Select
  833. // ======================================================================================
  834. function SelectField() { } SelectField.prototype = new Field();
  835. SelectField.prototype.make_input = function() {
  836. var me = this;
  837. var opt=[];
  838. if(this.in_filter && (!this.df.single_select)) {
  839. // multiple select
  840. this.input = $a(this.input_area, 'select');
  841. this.input.multiple = true;
  842. this.input.style.height = '4em';
  843. this.input.lab = $a(this.input_area, 'div', {fontSize:'9px',color:'#999'});
  844. this.input.lab.innerHTML = '(Use Ctrl+Click to select multiple or de-select)'
  845. } else {
  846. // Single select
  847. this.input = $a(this.input_area, 'select');
  848. this.input.onchange = function() {
  849. if(me.validate)
  850. me.validate();
  851. me.set(sel_val(this));
  852. me.run_trigger();
  853. }
  854. if(this.df.options == 'attach_files:') {
  855. this.file_attach = true;
  856. $(this.input).css({"width": "70%"});
  857. $("<button class='btn' title='Add attachment'\
  858. style='margin-bottom: 9px; \
  859. padding-left: 6px; padding-right: 6px; margin-left: 6px;'>\
  860. <i class='icon-plus'></i></button>")
  861. .click(function() {
  862. cur_frm.attachments.new_attachment();
  863. })
  864. .appendTo(this.input_area);
  865. }
  866. }
  867. // set as single (to be called from report builder)
  868. this.set_as_single = function() {
  869. var i = this.input;
  870. i.multiple = false;
  871. i.style.height = null;
  872. if(i.lab)$dh(i.lab)
  873. }
  874. // refresh options list
  875. this.refresh_options = function(options) {
  876. if(options)
  877. me.df.options = options;
  878. if(this.file_attach)
  879. this.set_attach_options();
  880. if(typeof me.df.options=="object")
  881. me.options_list = me.df.options || [""];
  882. else
  883. me.options_list = me.df.options?me.df.options.split('\n'):[''];
  884. // add options
  885. if(me.in_filter && me.options_list[0]!='') {
  886. me.options_list = add_lists([''], me.options_list);
  887. }
  888. $(this.input).empty().add_options(me.options_list);
  889. }
  890. // refresh options
  891. this.onrefresh = function() {
  892. this.refresh_options();
  893. if(this.not_in_form) {
  894. this.input.value = '';
  895. return;
  896. }
  897. if(_f.get_value)
  898. var v = _f.get_value(this.doctype,this.docname,this.df.fieldname);
  899. else {
  900. if(this.options_list && this.options_list.length)
  901. var v = this.options_list[0];
  902. else
  903. var v = null;
  904. }
  905. this.input.set_input(v);
  906. }
  907. this.input.set_input=function(v) {
  908. if(!v) {
  909. if(!me.input.multiple) {
  910. if(me.docname) { // if called from onload without docname being set on fields
  911. if(me.options_list && me.options_list.length) {
  912. me.set(me.options_list[0]);
  913. me.input.value = me.options_list[0];
  914. } else {
  915. me.input.value = '';
  916. }
  917. }
  918. }
  919. } else {
  920. if(me.options_list) {
  921. if(me.input.multiple) {
  922. for(var i=0; i<me.input.options.length; i++) {
  923. me.input.options[i].selected = 0;
  924. if(me.input.options[i].value && inList(typeof(v)=='string'?v.split(","):v, me.input.options[i].value))
  925. me.input.options[i].selected = 1;
  926. }
  927. } else if(in_list(me.options_list, v)){
  928. me.input.value = v;
  929. }
  930. }
  931. }
  932. }
  933. this.get_value= function() {
  934. if(me.input.multiple) {
  935. var l = [];
  936. for(var i=0;i<me.input.options.length; i++ ) {
  937. if(me.input.options[i].selected)l[l.length] = me.input.options[i].value;
  938. }
  939. return l;
  940. } else {
  941. if(me.input.options) {
  942. var val = sel_val(me.input);
  943. if(!val && !me.input.selectedIndex)
  944. val = me.input.options[0].value;
  945. return val;
  946. }
  947. return me.input.value;
  948. }
  949. }
  950. this.set_attach_options = function() {
  951. if(!cur_frm) return;
  952. var fl = cur_frm.doc.file_list;
  953. if(fl) {
  954. this.df.options = '';
  955. var fl = fl.split('\n');
  956. for(var i in fl) {
  957. this.df.options += '\n' + fl[i].split(',')[0];
  958. this.set_description("");
  959. }
  960. } else {
  961. this.df.options = ''
  962. this.set_description(wn._("Please attach a file first."))
  963. }
  964. }
  965. this.refresh();
  966. }
  967. function TimeField() { } TimeField.prototype = new DataField();
  968. function import_timepicker() {
  969. wn.require("lib/js/lib/jquery/jquery.ui.slider.min.js");
  970. wn.require("lib/js/lib/jquery/jquery.ui.sliderAccess.js");
  971. wn.require("lib/js/lib/jquery/jquery.ui.timepicker-addon.css");
  972. wn.require("lib/js/lib/jquery/jquery.ui.timepicker-addon.js");
  973. }
  974. TimeField.prototype.make_input = function() {
  975. import_timepicker();
  976. var me = this;
  977. this.input = $('<input type="text">')
  978. .appendTo(this.input_area)
  979. .timepicker({
  980. timeFormat: 'hh:mm:ss',
  981. }).get(0);
  982. this.input.set_input = function(v) {
  983. $(me.input).val(v);
  984. };
  985. this.input.onchange = function() {
  986. if(!this.not_in_form)
  987. me.set(me.input.value);
  988. me.run_trigger();
  989. };
  990. }
  991. function DateTimeField() { } DateTimeField.prototype = new DateField();
  992. DateTimeField.prototype.make_input = function() {
  993. import_timepicker();
  994. var me = this;
  995. args = get_datepicker_options();
  996. args.timeFormat = "hh:mm:ss";
  997. this.input = $('<input type="text">')
  998. .appendTo(this.input_area)
  999. .datetimepicker(args).get(0);
  1000. this.setup_input();
  1001. }
  1002. var tmpid = 0;
  1003. _f.ButtonField = function() { };
  1004. _f.ButtonField.prototype = new Field();
  1005. _f.ButtonField.prototype.with_label = 0;
  1006. _f.ButtonField.prototype.make_input = function() { var me = this;
  1007. // make a button area for one button
  1008. if(!this.button_area)
  1009. this.button_area = $a(this.input_area, 'div','',{
  1010. marginBottom:'4px'});
  1011. // make the input
  1012. this.input = $btn(this.button_area,
  1013. me.df.label, null,
  1014. {fontWeight:'bold'}, null, 1)
  1015. $(this.input).click(function() {
  1016. if(me.not_in_form) return;
  1017. if(cur_frm.cscript[me.df.fieldname] && (!me.in_filter)) {
  1018. cur_frm.runclientscript(me.df.fieldname, me.doctype, me.docname);
  1019. } else {
  1020. cur_frm.runscript(me.df.options, me);
  1021. }
  1022. });
  1023. }
  1024. _f.ButtonField.prototype.hide = function() {
  1025. $dh(this.button_area);
  1026. };
  1027. _f.ButtonField.prototype.show = function() {
  1028. $ds(this.button_area);
  1029. };
  1030. _f.ButtonField.prototype.set = function(v) { }; // No Setter
  1031. _f.ButtonField.prototype.set_disp = function(val) { } // No Disp on readonly
  1032. function make_field(docfield, doctype, parent, frm, in_grid, hide_label) { // Factory
  1033. switch(docfield.fieldtype.toLowerCase()) {
  1034. // general fields
  1035. case 'data':var f = new DataField(); break;
  1036. case 'password':var f = new DataField(); break;
  1037. case 'int':var f = new IntField(); break;
  1038. case 'float':var f = new FloatField(); break;
  1039. case 'currency':var f = new CurrencyField(); break;
  1040. case 'percent':var f = new PercentField(); break;
  1041. case 'read only':var f = new ReadOnlyField(); break;
  1042. case 'link':var f = new LinkField(); break;
  1043. case 'long text': var f = new TextField(); break;
  1044. case 'date':var f = new DateField(); break;
  1045. case 'datetime':var f = new DateTimeField(); break;
  1046. case 'time':var f = new TimeField(); break;
  1047. case 'html':var f = new HTMLField(); break;
  1048. case 'check':var f = new CheckField(); break;
  1049. case 'text':var f = new TextField(); break;
  1050. case 'small text':var f = new TextField(); break;
  1051. case 'select':var f = new SelectField(); break;
  1052. case 'button':var f = new _f.ButtonField(); break;
  1053. // form fields
  1054. case 'code':var f = new _f.CodeField(); break;
  1055. case 'text editor':var f = new _f.CodeField(); break;
  1056. case 'table':var f = new _f.TableField(); break;
  1057. case 'section break':var f= new _f.SectionBreak(); break;
  1058. case 'column break':var f= new _f.ColumnBreak(); break;
  1059. case 'image':var f= new _f.ImageField(); break;
  1060. }
  1061. f.parent = parent;
  1062. f.doctype = doctype;
  1063. f.df = docfield;
  1064. f.perm = frm ? frm.perm : [[1,1,1]];
  1065. if(_f)
  1066. f.col_break_width = _f.cur_col_break_width;
  1067. if(in_grid) {
  1068. f.in_grid = true;
  1069. f.with_label = 0;
  1070. }
  1071. if(hide_label) {
  1072. f.with_label = 0;
  1073. }
  1074. if(frm) {
  1075. f.frm = frm;
  1076. if(parent)
  1077. f.layout_cell = parent.parentNode;
  1078. }
  1079. if(f.init) f.init();
  1080. f.make_body();
  1081. return f;
  1082. }