Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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