您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

12 年前
12 年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Copyright 2013 Web Notes Technologies Pvt Ltd
  2. // License: MIT. See license.txt
  3. wn.views.get_listview = function(doctype, parent) {
  4. var meta = locals.DocType[doctype];
  5. if(wn.doclistviews[doctype]) {
  6. var listview = new wn.doclistviews[doctype](parent);
  7. } else {
  8. var listview = new wn.views.ListView(parent, doctype);
  9. }
  10. return listview;
  11. }
  12. wn.provide("wn.listview_settings");
  13. wn.views.ListView = Class.extend({
  14. init: function(doclistview, doctype) {
  15. this.doclistview = doclistview;
  16. this.doctype = doctype;
  17. this.settings = wn.listview_settings[this.doctype] || {};
  18. this.set_fields();
  19. this.set_columns();
  20. if(this.settings.group_by)
  21. this.group_by = this.settings.group_by;
  22. var me = this;
  23. this.doclistview.onreset = function() {
  24. me.id_list = [];
  25. }
  26. },
  27. set_fields: function() {
  28. var me = this;
  29. var t = "`tab"+this.doctype+"`.";
  30. this.fields = [t + 'name', t + 'owner', t + 'docstatus',
  31. t + '_user_tags', t + 'modified', t + 'modified_by'];
  32. this.stats = ['_user_tags'];
  33. // add workflow field (as priority)
  34. this.workflow_state_fieldname = wn.workflow.get_state_fieldname(this.doctype);
  35. if(this.workflow_state_fieldname) {
  36. this.fields.push(t + this.workflow_state_fieldname);
  37. this.stats.push(this.workflow_state_fieldname);
  38. }
  39. $.each(wn.model.get("DocField", {"parent":this.doctype, "in_list_view":1}), function(i,d) {
  40. if(wn.perm.has_perm(me.doctype, d.permlevel, READ)) {
  41. if(d.fieldtype=="Image" && d.options) {
  42. me.fields.push(t + "`" + d.options + "`");
  43. } else {
  44. me.fields.push(t + "`" + d.fieldname + "`");
  45. }
  46. if(d.fieldtype=="Select") {
  47. me.stats.push(d.fieldname);
  48. }
  49. // currency field for symbol (multi-currency)
  50. if(d.fieldtype=="Currency" && d.options) {
  51. if(d.options.indexOf(":")!=-1) {
  52. me.fields.push(t + "`" + d.options.split(":")[1] + "`");
  53. } else {
  54. me.fields.push(t + "`" + d.options + "`");
  55. };
  56. }
  57. }
  58. });
  59. // additional fields
  60. if(this.settings.add_fields) {
  61. $.each(this.settings.add_fields, function(i, d) {
  62. if(me.fields.indexOf(d)==-1)
  63. me.fields.push(d);
  64. });
  65. }
  66. },
  67. set_columns: function() {
  68. this.columns = [];
  69. var me = this;
  70. this.columns.push({colspan: 1, content:'avatar'});
  71. this.columns.push({colspan: 3, content:'name'});
  72. if(this.workflow_state_fieldname) {
  73. this.columns.push({
  74. colspan: 2,
  75. content: this.workflow_state_fieldname,
  76. type:"select"
  77. });
  78. }
  79. // overridden
  80. var overridden = $.map(this.settings.add_columns || [], function(d) {
  81. return d.content;
  82. });
  83. $.each(wn.model.get("DocField", {"parent":this.doctype, "in_list_view":1}),
  84. function(i,d) {
  85. if(in_list(overridden, d.fieldname)) {
  86. return;
  87. }
  88. // field width
  89. var colspan = "2";
  90. if(in_list(["Int", "Percent"], d.fieldtype)) {
  91. colspan = "1";
  92. } else if(d.fieldtype=="Check") {
  93. colspan = "1";
  94. } else if(in_list(["name", "subject", "title"], d.fieldname)) { // subjects are longer
  95. colspan = "3";
  96. } else if(d.fieldtype=="Text Editor" || d.fieldtype=="Text") {
  97. colspan = "3";
  98. }
  99. me.columns.push({colspan: colspan, content: d.fieldname,
  100. type:d.fieldtype, df:d, title:wn._(d.label) });
  101. });
  102. // additional columns
  103. if(this.settings.add_columns) {
  104. $.each(this.settings.add_columns, function(i, d) {
  105. me.columns.push(d);
  106. });
  107. }
  108. // expand "name" if there are few columns
  109. var total_colspan = 0;
  110. $.each(this.columns, function(i, c) { total_colspan += cint(c.colspan); });
  111. if(total_colspan < 8) {
  112. $.each(this.columns,
  113. function(i, c) { if(c.content==="name") { c.colspan = 4; return false; } });
  114. }
  115. },
  116. render: function(row, data) {
  117. this.prepare_data(data);
  118. $(row).removeClass("list-row");
  119. // maintain id_list to avoid duplication incase
  120. // of filtering by child table
  121. if(in_list(this.id_list, data.name))
  122. return;
  123. else
  124. this.id_list.push(data.name);
  125. var body = $("<div class='row doclist-row'></div>")
  126. .appendTo(row).css({"padding": "5px 0px",
  127. "padding-bottom": "0px",
  128. "margin-bottom": "5px",
  129. "border-bottom": "1px solid #eee"
  130. }),
  131. colspans = 0,
  132. me = this;
  133. // make table
  134. $.each(this.columns, function(i, v) {
  135. var colspan = v.colspan || 2;
  136. colspans = colspans + flt(colspan)
  137. if(colspans <= 6) {
  138. var col = me.make_column(body, flt(colspan) * 2, true).addClass("visible-sm");
  139. me.render_column(data, col, v);
  140. }
  141. if(colspans <= 12) {
  142. var col = me.make_column(body, colspan)
  143. .addClass("hidden-sm");
  144. me.render_column(data, col, v);
  145. }
  146. });
  147. // row #2
  148. var row2 = $('<div class="col col-lg-12">\
  149. <div class="row">\
  150. <div class="col col-lg-7 col-offset-3">\
  151. <div class="list-tag hidden-sm"></div></div>\
  152. <div class="col col-lg-2 timestamp" style="font-size: 90%; padding-right: 4px;\
  153. color: #aaa; margin-top: -3px; text-align: right;">\
  154. </div>\
  155. </div>\
  156. </div>').appendTo(body);
  157. // modified
  158. row2.find(".timestamp").html(comment_when(data.modified));
  159. // add tags
  160. var tag_editor = new wn.ui.TagEditor({
  161. parent: row2.find(".list-tag"),
  162. doctype: this.doctype,
  163. docname: data.name,
  164. user_tags: data._user_tags
  165. });
  166. tag_editor.$w.on("click", ".tagit-label", function() {
  167. me.doclistview.set_filter("_user_tags",
  168. $(this).text());
  169. });
  170. },
  171. make_column: function(body, colspan, is_small) {
  172. var col = $("<div>")
  173. .appendTo(body)
  174. .addClass(is_small ? ("col col-sm-" + cint(colspan)) : ("col col-lg-" + cint(colspan)))
  175. .css({
  176. "white-space": "nowrap",
  177. "text-overflow": "ellipsis",
  178. "max-height": "30px",
  179. "padding-right": "0px"
  180. })
  181. return col;
  182. },
  183. render_column: function(data, parent, opts) {
  184. var me = this;
  185. if(opts.type) opts.type= opts.type.toLowerCase();
  186. // style
  187. if(opts.css) {
  188. $.each(opts.css, function(k, v) { $(parent).css(k, v)});
  189. }
  190. // multiple content
  191. if(opts.content.indexOf && opts.content.indexOf('+')!=-1) {
  192. $.map(opts.content.split('+'), function(v) {
  193. me.render_column(data, parent, {content:v, title: opts.title});
  194. });
  195. return;
  196. }
  197. // content
  198. if(typeof opts.content=='function') {
  199. opts.content(parent, data, me);
  200. }
  201. else if(opts.content=='name') {
  202. if(wn.model.is_submittable(this.doctype)) {
  203. $(parent).append(repl('<span class="docstatus" style="margin-right: 3px;"> \
  204. <i class="%(docstatus_icon)s" \
  205. title="%(docstatus_title)s"></i></span>', data));
  206. }
  207. $("<a>")
  208. .attr("href", "#Form/" + data.doctype + "/" + encodeURIComponent(data.name))
  209. .html(data.name)
  210. .appendTo(parent.css({"overflow":"hidden"}));
  211. }
  212. else if(opts.content=='avatar' || opts.content=='avatar_modified') {
  213. if(wn.model.can_delete(this.doctype) || this.settings.selectable) {
  214. $('<input class="list-delete" type="checkbox">')
  215. .data('name', data.name)
  216. .data('data', data)
  217. .css({"margin-right": "5px", "margin-left": "-2px"})
  218. .appendTo(parent)
  219. }
  220. $(parent).append(wn.avatar(data.modified_by, false, wn._("Modified by")+": "
  221. + wn.user_info(data.modified_by).fullname))
  222. .css({"margin-top": "-5px"});
  223. }
  224. else if(opts.content=='check') {
  225. }
  226. else if(opts.type=='bar-graph' || opts.type=="percent") {
  227. this.render_bar_graph(parent, data, opts.content, opts.label);
  228. }
  229. else if(opts.template) {
  230. $(parent).append(repl(opts.template, data));
  231. }
  232. else if(opts.type=="date" && data[opts.content]) {
  233. $("<span>")
  234. .html(wn.datetime.str_to_user(data[opts.content]))
  235. .css({"color":"#888"})
  236. .appendTo(parent);
  237. }
  238. else if(opts.type=="image") {
  239. data[opts.content] = data[opts.df.options];
  240. if(data[opts.content])
  241. $("<img>")
  242. .attr("src", wn.utils.get_file_link(data[opts.content]))
  243. .css({
  244. "max-width": "100px",
  245. "max-height": "30px"
  246. })
  247. .appendTo(parent);
  248. }
  249. else if(opts.type=="select" && data[opts.content]) {
  250. var label_class = "";
  251. var style = wn.utils.guess_style(data[opts.content]);
  252. if(style) label_class = "label-" + style;
  253. $("<span class='label'>"
  254. + data[opts.content] + "</span>")
  255. .css({"cursor":"pointer"})
  256. .addClass(label_class)
  257. .attr("data-fieldname", opts.content)
  258. .click(function() {
  259. me.doclistview.set_filter($(this).attr("data-fieldname"),
  260. $(this).text());
  261. })
  262. .appendTo(parent.css({"overflow":"hidden"}));
  263. }
  264. else if(data[opts.content]) {
  265. $("<span>")
  266. .html(wn.format(data[opts.content], opts.df, null, data))
  267. .appendTo(parent.css({"overflow":"hidden"}))
  268. }
  269. // finally
  270. if(!$(parent).html()) {
  271. $("<span>-</span>").css({color:"#ccc"}).appendTo(parent);
  272. }
  273. // title
  274. if(!in_list(["avatar", "_user_tags", "check"], opts.content)) {
  275. if($(parent).attr("title")==undefined) {
  276. $(parent).attr("title", (opts.title || opts.content) + ": "
  277. + (data[opts.content] || "Not Set"))
  278. }
  279. $(parent).tooltip();
  280. }
  281. },
  282. show_hide_check_column: function() {
  283. if(!this.doclistview.can_delete) {
  284. this.columns = $.map(this.columns, function(v, i) { if(v.content!='check') return v });
  285. }
  286. },
  287. prepare_data: function(data) {
  288. if(data.modified)
  289. this.prepare_when(data, data.modified);
  290. // docstatus
  291. if(data.docstatus==0 || data.docstatus==null) {
  292. data.docstatus_icon = 'icon-check-empty';
  293. data.docstatus_title = wn._('Editable');
  294. } else if(data.docstatus==1) {
  295. data.docstatus_icon = 'icon-lock';
  296. data.docstatus_title = wn._('Submitted');
  297. } else if(data.docstatus==2) {
  298. data.docstatus_icon = 'icon-remove';
  299. data.docstatus_title = wn._('Cancelled');
  300. }
  301. // nulls as strings
  302. for(key in data) {
  303. if(data[key]==null) {
  304. data[key]='';
  305. }
  306. }
  307. // prepare data in settings
  308. if(this.settings.prepare_data)
  309. this.settings.prepare_data(data);
  310. },
  311. prepare_when: function(data, date_str) {
  312. if (!date_str) date_str = data.modified;
  313. // when
  314. data.when = (dateutil.str_to_user(date_str)).split(' ')[0];
  315. var diff = dateutil.get_diff(dateutil.get_today(), date_str.split(' ')[0]);
  316. if(diff==0) {
  317. data.when = dateutil.comment_when(date_str);
  318. }
  319. if(diff == 1) {
  320. data.when = wn._('Yesterday')
  321. }
  322. if(diff == 2) {
  323. data.when = wn._('2 days ago')
  324. }
  325. },
  326. render_bar_graph: function(parent, data, field, label) {
  327. var args = {
  328. percent: data[field],
  329. label: label
  330. }
  331. $(parent).append(repl('<span class="progress" style="width: 100%; float: left;"> \
  332. <span class="progress-bar" title="%(percent)s% %(label)s" \
  333. style="width: %(percent)s%;"></span>\
  334. </span>', args));
  335. },
  336. render_icon: function(parent, icon_class, label) {
  337. var icon_html = "<i class='%(icon_class)s' title='%(label)s'></i>";
  338. $(parent).append(repl(icon_html, {icon_class: icon_class, label: label || ''}));
  339. }
  340. });
  341. // embeddable
  342. wn.provide('wn.views.RecordListView');
  343. wn.views.RecordListView = wn.views.DocListView.extend({
  344. init: function(doctype, wrapper, ListView) {
  345. this.doctype = doctype;
  346. this.wrapper = wrapper;
  347. this.listview = new ListView(this, doctype);
  348. this.listview.parent = this;
  349. this.setup();
  350. },
  351. setup: function() {
  352. var me = this;
  353. me.page_length = 10;
  354. $(me.wrapper).empty();
  355. me.init_list();
  356. },
  357. get_args: function() {
  358. var args = this._super();
  359. $.each((this.default_filters || []), function(i, f) {
  360. args.filters.push(f);
  361. });
  362. args.docstatus = args.docstatus.concat((this.default_docstatus || []));
  363. return args;
  364. },
  365. });