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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
  2. // MIT License. See license.txt
  3. wn.provide("wn.ui.form");
  4. wn.ui.form.Layout = Class.extend({
  5. init: function(opts) {
  6. this.views = {};
  7. this.sections = [];
  8. this.fields_list = [];
  9. this.fields_dict = {};
  10. this.labelled_section_count = 0;
  11. this.ignore_types = ["Section Break", "Column Break"];
  12. $.extend(this, opts);
  13. },
  14. make: function() {
  15. if(!this.parent && this.body)
  16. this.parent = this.body;
  17. this.wrapper = $('<div class="form-layout">').appendTo(this.parent);
  18. if(!this.fields)
  19. this.fields = wn.meta.docfield_map[this.doctype];
  20. this.setup_tabbing();
  21. this.render();
  22. },
  23. add_view: function(label) {
  24. var view = $('<div class="form-add-view">').appendTo(this.parent).toggle(false);
  25. this.views[label] = view;
  26. },
  27. set_view: function(label) {
  28. if(this.cur_view) this.cur_view.toggle(false);
  29. if(label) {
  30. this.wrapper.toggle(false);
  31. if(!this.views[label])
  32. this.add_view(label);
  33. this.cur_view = this.views[label].toggle(true);
  34. } else {
  35. this.wrapper.toggle(true);
  36. }
  37. },
  38. refresh: function() {
  39. var me = this;
  40. $.each(this.fields_list, function(i, fieldobj) {
  41. if(me.frm) {
  42. fieldobj.docname = me.frm.docname;
  43. fieldobj.df = wn.meta.get_docfield(me.frm.doctype,
  44. fieldobj.df.fieldname, me.frm.docname);
  45. // on form change, permissions can change
  46. fieldobj.perm = me.frm.perm;
  47. };
  48. fieldobj.refresh && fieldobj.refresh();
  49. });
  50. if(this.frm)
  51. $(this.frm.wrapper).trigger("refresh-fields");
  52. },
  53. render: function() {
  54. var me = this;
  55. this.section = null;
  56. this.column = null;
  57. if(this.fields[0] && this.fields[0].fieldtype!="Section Break") {
  58. this.make_section();
  59. }
  60. $.each(this.fields, function(i, df) {
  61. switch(df.fieldtype) {
  62. case "Section Break":
  63. me.make_section(df);
  64. break;
  65. case "Column Break":
  66. me.make_column(df);
  67. break;
  68. default:
  69. me.make_field(df);
  70. }
  71. });
  72. },
  73. make_column: function(df) {
  74. this.column = $('<div class="form-column">\
  75. <form>\
  76. <fieldset></fieldset>\
  77. </form>\
  78. </div>').appendTo(this.section.body)
  79. .find("form")
  80. .on("submit", function() { return false; })
  81. .find("fieldset");
  82. // distribute all columns equally
  83. var colspan = cint(12 / this.section.find(".form-column").length);
  84. this.section.find(".form-column").removeClass()
  85. .addClass("form-column")
  86. .addClass("col-md-" + colspan);
  87. },
  88. make_field: function(df, colspan) {
  89. !this.column && this.make_column();
  90. var fieldobj = make_field(df, this.doctype, this.column.get(0), this.frm);
  91. this.fields_list.push(fieldobj);
  92. this.fields_dict[df.fieldname] = fieldobj;
  93. if(this.frm) {
  94. fieldobj.perm = this.frm.perm;
  95. }
  96. },
  97. make_section: function(df) {
  98. if(this.section) {
  99. //$("<hr>").appendTo(this.wrapper);
  100. }
  101. this.section = $('<div class="row">')
  102. .appendTo(this.wrapper);
  103. this.sections.push(this.section);
  104. var section = this.section[0];
  105. section.df = df;
  106. if(df) {
  107. if(df.label) {
  108. this.labelled_section_count++;
  109. $('<h3 class="col-md-12">'
  110. + (df.options ? (' <i class="text-muted '+df.options+'"></i> ') : "")
  111. + '<span class="section-count-label">' + this.labelled_section_count + "</span>. "
  112. + wn._(df.label)
  113. + "</h3>")
  114. .css({
  115. "font-weight": "bold",
  116. })
  117. .appendTo(this.section);
  118. if(this.sections.length > 1)
  119. this.section.css({
  120. "margin-top": "15px",
  121. "border-top": "1px solid #ddd"
  122. });
  123. }
  124. if(df.description) {
  125. $('<div class="col-md-12 small text-muted">' + df.description + '</div>')
  126. .css("padding-left", "40px")
  127. .appendTo(this.section);
  128. }
  129. if(df.label || df.description) {
  130. // spacer
  131. $('<div class="col-md-12"></div>')
  132. .appendTo(this.section)
  133. .css({"height": "20px"});
  134. }
  135. this.fields_dict[df.fieldname] = section;
  136. this.fields_list.push(section);
  137. }
  138. // for bc
  139. this.section.body = $('<div style="padding: 0px 3%">').appendTo(this.section);
  140. section.row = {
  141. wrapper: section
  142. };
  143. section.refresh = function() {
  144. $(this).toggle(!this.df.hidden)
  145. }
  146. this.column = null;
  147. if(df && df.hidden) {
  148. this.section.toggle(false);
  149. }
  150. return this.section;
  151. },
  152. refresh_section_count: function() {
  153. this.wrapper.find(".section-count-label:visible").each(function(i) {
  154. $(this).html(i+1);
  155. });
  156. },
  157. setup_tabbing: function() {
  158. var me = this;
  159. this.wrapper.on("keydown", function(ev) {
  160. if(ev.which==9) {
  161. var current = $(ev.target).trigger("change"),
  162. doctype = current.attr("data-doctype"),
  163. fieldname = current.attr("data-fieldname");
  164. if(doctype)
  165. return me.handle_tab(doctype, fieldname, ev.shiftKey);
  166. }
  167. })
  168. },
  169. handle_tab: function(doctype, fieldname, shift) {
  170. var me = this,
  171. grid_row = null;
  172. prev = null,
  173. fields = me.fields,
  174. in_grid = false;
  175. // in grid
  176. if(doctype != me.doctype) {
  177. grid_row =me.get_open_grid_row()
  178. fields = grid_row.fields;
  179. }
  180. for(var i=0, len=fields.length; i < len; i++) {
  181. if(fields[i].df.fieldname==fieldname) {
  182. if(shift) {
  183. if(prev) {
  184. this.set_focus(prev)
  185. } else {
  186. $(this.primary_button).focus();
  187. }
  188. break;
  189. }
  190. if(i==len-1) {
  191. // last field in this group
  192. if(grid_row) {
  193. // in grid
  194. if(grid_row.doc.idx==grid_row.grid.grid_rows.length) {
  195. // last row, close it and find next field
  196. grid_row.toggle_view(false, function() {
  197. me.handle_tab(grid_row.grid.df.parent, grid_row.grid.df.fieldname);
  198. })
  199. } else {
  200. // next row
  201. grid_row.grid.grid_rows[grid_row.doc.idx].toggle_view(true);
  202. }
  203. } else {
  204. $(this.primary_button).focus();
  205. }
  206. } else {
  207. me.focus_on_next_field(i, fields);
  208. }
  209. break;
  210. }
  211. if(fields[i].disp_status==="Write")
  212. prev = fields[i];
  213. }
  214. return false;
  215. },
  216. focus_on_next_field: function(start_idx, fields) {
  217. // loop to find next eligible fields
  218. for(var i= start_idx + 1, len = fields.length; i < len; i++) {
  219. if(fields[i].disp_status==="Write" && !in_list(wn.model.no_value_type, fields[i].df.fieldtype)) {
  220. this.set_focus(fields[i]);
  221. break;
  222. }
  223. }
  224. },
  225. set_focus: function(field) {
  226. // next is table, show the table
  227. if(field.df.fieldtype=="Table") {
  228. if(!field.grid.grid_rows.length) {
  229. field.grid.add_new_row(1);
  230. } else {
  231. field.grid.grid_rows[0].toggle_view(true);
  232. }
  233. }
  234. else if(field.editor) {
  235. field.editor.set_focus();
  236. }
  237. else if(field.$input) {
  238. field.$input.focus();
  239. }
  240. },
  241. get_open_grid_row: function() {
  242. return $(".grid-row-open").data("grid_row");
  243. },
  244. })