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.

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