25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

472 satır
13 KiB

  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 = [];
  31. this.stats = ['_user_tags'];
  32. var add_field = function(fieldname) {
  33. field = t + "`" + fieldname + "`"
  34. if(me.fields.indexOf(field)=== -1)
  35. me.fields.push(field);
  36. }
  37. $.each(['name', 'owner', 'docstatus', '_user_tags', '_comments', 'modified',
  38. 'modified_by'], function(i, fieldname) { add_field(fieldname); })
  39. // add title field
  40. var meta = wn.model.get("DocType", this.doctype)[0];
  41. if(meta.title_field) {
  42. this.title_field = meta.title_field;
  43. add_field(meta.title_field);
  44. }
  45. // add workflow field (as priority)
  46. this.workflow_state_fieldname = wn.workflow.get_state_fieldname(this.doctype);
  47. if(this.workflow_state_fieldname) {
  48. add_field(this.workflow_state_fieldname);
  49. this.stats.push(this.workflow_state_fieldname);
  50. }
  51. $.each(wn.model.get("DocField", {"parent":this.doctype, "in_list_view":1}), function(i,d) {
  52. if(wn.perm.has_perm(me.doctype, d.permlevel, "read")) {
  53. if(d.fieldtype=="Image" && d.options) {
  54. add_field(d.options);
  55. } else {
  56. add_field(d.fieldname);
  57. }
  58. if(d.fieldtype=="Select") {
  59. if(me.stats.indexOf(d.fieldname)===-1) me.stats.push(d.fieldname);
  60. }
  61. // currency field for symbol (multi-currency)
  62. if(d.fieldtype=="Currency" && d.options) {
  63. if(d.options.indexOf(":")!=-1) {
  64. add_field(d.options.split(":")[1]);
  65. } else {
  66. add_field(d.options);
  67. };
  68. }
  69. }
  70. });
  71. // additional fields
  72. if(this.settings.add_fields) {
  73. $.each(this.settings.add_fields, function(i, d) {
  74. if(me.fields.indexOf(d)==-1)
  75. me.fields.push(d);
  76. });
  77. }
  78. },
  79. set_columns: function() {
  80. this.columns = [];
  81. this.total_colspans = 0;
  82. var me = this;
  83. if(this.workflow_state_fieldname) {
  84. this.columns.push({
  85. colspan: 3,
  86. content: this.workflow_state_fieldname,
  87. type:"select"
  88. });
  89. }
  90. // overridden
  91. var overridden = $.map(this.settings.add_columns || [], function(d) {
  92. return d.content;
  93. });
  94. var docfields_in_list_view = wn.model.get("DocField", {"parent":this.doctype,
  95. "in_list_view":1}).sort(function(a, b) { return a.idx - b.idx })
  96. $.each(docfields_in_list_view, function(i,d) {
  97. if(in_list(overridden, d.fieldname) || d.fieldname === me.title_field) {
  98. return;
  99. }
  100. // field width
  101. var colspan = "3";
  102. if(in_list(["Int", "Percent", "Select"], d.fieldtype)) {
  103. colspan = "2";
  104. } else if(d.fieldtype=="Check") {
  105. colspan = "1";
  106. } else if(in_list(["name", "subject", "title"], d.fieldname)) { // subjects are longer
  107. colspan = "4";
  108. } else if(d.fieldtype=="Text Editor" || d.fieldtype=="Text") {
  109. colspan = "4";
  110. }
  111. me.total_colspans += parseInt(colspan);
  112. me.columns.push({colspan: colspan, content: d.fieldname,
  113. type:d.fieldtype, df:d, title:wn._(d.label) });
  114. });
  115. // additional columns
  116. if(this.settings.add_columns) {
  117. $.each(this.settings.add_columns, function(i, d) {
  118. me.columns.push(d);
  119. me.total_colspans += parseInt(d.colspan);
  120. });
  121. }
  122. var empty_cols = flt(12 - this.total_colspans);
  123. this.shift_right = cint(empty_cols * 0.6667);
  124. if(this.shift_right < 0) {
  125. this.shift_right = 0;
  126. } else if (this.shift_right > 1) {
  127. // expand each column so that it fills up empty_cols
  128. $.each(this.columns, function(i, c) {
  129. c.colspan = cint(empty_cols / me.columns.length) + cint(c.colspan);
  130. })
  131. }
  132. },
  133. render: function(row, data) {
  134. this.prepare_data(data);
  135. //$(row).removeClass("list-row");
  136. // maintain id_list to avoid duplication incase
  137. // of filtering by child table
  138. if(in_list(this.id_list, data.name)) {
  139. return;
  140. } else {
  141. this.id_list.push(data.name);
  142. }
  143. var left_cols = 4 + this.shift_right, right_cols = 8 - this.shift_right;
  144. var body = $('<div class="doclist-row row">\
  145. <div class="list-row-id-area col-sm-'+left_cols+'" style="white-space: nowrap;\
  146. text-overflow: ellipsis; max-height: 30px"></div>\
  147. <div class="list-row-content-area col-sm-'+right_cols+'"></div>\
  148. </div>').appendTo($(row).css({"position":"relative"})),
  149. colspans = 0,
  150. me = this;
  151. me.render_avatar_and_id(data, body.find(".list-row-id-area"))
  152. // make table
  153. $.each(this.columns, function(i, v) {
  154. var colspan = v.colspan || 3;
  155. colspans = colspans + flt(colspan)
  156. if(colspans <= 12) {
  157. var col = me.make_column(body.find(".list-row-content-area"), colspan);
  158. me.render_column(data, col, v);
  159. }
  160. });
  161. var comments = data._comments ? JSON.parse(data._comments) : [];
  162. var tags = $.map((data._user_tags || "").split(","), function(v) { return v ? v : null; });
  163. var timestamp_and_comment =
  164. $('<div class="list-timestamp">')
  165. .appendTo(row)
  166. .html(""
  167. + (tags.length ? (
  168. '<span style="margin-right: 10px;" class="list-tag-preview">' + tags.join(", ") + '</span>'
  169. ): "")
  170. + (comments.length ?
  171. ('<a style="margin-right: 10px;" href="#Form/'+
  172. this.doctype + '/' + data.name
  173. +'" title="'+
  174. comments[comments.length-1].comment
  175. +'"><i class="icon-comments"></i> '
  176. + comments.length + " " + (
  177. comments.length===1 ? wn._("comment") : wn._("comments")) + '</a>')
  178. : "")
  179. + comment_when(data.modified));
  180. // row #2
  181. var row2 = $('<div class="row tag-row" style="margin-bottom: 5px;">\
  182. <div class="col-xs-12">\
  183. <div class="col-xs-3"></div>\
  184. <div class="col-xs-7">\
  185. <div class="list-tag xs-hidden"></div>\
  186. <div class="list-last-modified text-muted xs-visible"></div>\
  187. </div>\
  188. </div>\
  189. </div>').appendTo(row);
  190. // modified
  191. body.find(".list-last-modified").html(wn._("Last updated by") + ": " + wn.user_info(data.modified_by).fullname);
  192. if(!me.doclistview.tags_shown) {
  193. row2.addClass("hide");
  194. }
  195. // add tags
  196. var tag_editor = new wn.ui.TagEditor({
  197. parent: row2.find(".list-tag"),
  198. frm: {
  199. doctype: this.doctype,
  200. docname: data.name
  201. },
  202. user_tags: data._user_tags
  203. });
  204. tag_editor.$w.on("click", ".tagit-label", function() {
  205. me.doclistview.set_filter("_user_tags",
  206. $(this).text());
  207. });
  208. },
  209. make_column: function(body, colspan) {
  210. var col = $("<div class='col'>")
  211. .appendTo(body)
  212. .addClass("col-sm-" + cint(colspan))
  213. .css({
  214. "white-space": "nowrap",
  215. "text-overflow": "ellipsis",
  216. "height": "30px",
  217. "padding-top":"3px"
  218. })
  219. return col;
  220. },
  221. render_avatar_and_id: function(data, parent) {
  222. if((wn.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete) {
  223. $('<input class="list-delete" type="checkbox">')
  224. .data('name', data.name)
  225. .data('data', data)
  226. .css({"margin-right": "5px"})
  227. .appendTo(parent)
  228. }
  229. var $avatar = $(wn.avatar(data.modified_by, false, wn._("Modified by")+": "
  230. + wn.user_info(data.modified_by).fullname))
  231. .appendTo(parent)
  232. .css({"max-width": "100%"})
  233. if(wn.model.is_submittable(this.doctype)) {
  234. $(parent).append(repl('<span class="docstatus" style="margin-right: 3px;"> \
  235. <i class="%(docstatus_icon)s" \
  236. title="%(docstatus_title)s"></i></span>', data));
  237. }
  238. var title = data[this.title_field || "name"];
  239. $("<a>")
  240. .attr("href", "#Form/" + data.doctype + "/" + encodeURIComponent(data.name))
  241. .html(title)
  242. .appendTo(parent.css({"overflow":"hidden"}));
  243. parent.attr("title", title).tooltip();
  244. },
  245. render_column: function(data, parent, opts) {
  246. var me = this;
  247. if(opts.type) opts.type= opts.type.toLowerCase();
  248. // style
  249. if(opts.css) {
  250. $.each(opts.css, function(k, v) { $(parent).css(k, v)});
  251. }
  252. // multiple content
  253. if(opts.content.indexOf && opts.content.indexOf('+')!=-1) {
  254. $.map(opts.content.split('+'), function(v) {
  255. me.render_column(data, parent, {content:v, title: opts.title});
  256. });
  257. return;
  258. }
  259. // content
  260. if(typeof opts.content=='function') {
  261. opts.content(parent, data, me);
  262. }
  263. else if(opts.content=='check') {
  264. }
  265. else if(opts.type=='bar-graph' || opts.type=="percent") {
  266. this.render_bar_graph(parent, data, opts.content, opts.label);
  267. }
  268. else if(opts.template) {
  269. $(parent).append(repl(opts.template, data));
  270. }
  271. else if(opts.type=="date" && data[opts.content]) {
  272. $("<span>")
  273. .html(wn.datetime.str_to_user(data[opts.content]))
  274. .css({"color":"#888"})
  275. .appendTo(parent);
  276. }
  277. else if(opts.type=="image") {
  278. data[opts.content] = data[opts.df.options];
  279. if(data[opts.content])
  280. $("<img>")
  281. .attr("src", wn.utils.get_file_link(data[opts.content]))
  282. .css({
  283. "max-width": "100%",
  284. "max-height": "30px"
  285. })
  286. .appendTo(parent);
  287. }
  288. else if(opts.type=="select" && data[opts.content]) {
  289. var label_class = "label-default";
  290. var style = wn.utils.guess_style(data[opts.content]);
  291. if(style) label_class = "label-" + style;
  292. $("<span>"
  293. + data[opts.content] + "</span>")
  294. .css({"cursor":"pointer"})
  295. .addClass("label")
  296. .addClass(label_class)
  297. .attr("data-fieldname", opts.content)
  298. .click(function() {
  299. me.doclistview.set_filter($(this).attr("data-fieldname"),
  300. $(this).text());
  301. })
  302. .appendTo(parent.css({"overflow":"hidden"}));
  303. }
  304. else if(opts.type=="link" && data[opts.content]) {
  305. $("<span>")
  306. .html(wn.format(data[opts.content], opts.df, null, data))
  307. .appendTo(parent.css({"overflow":"hidden"}))
  308. .click(function() {
  309. me.doclistview.set_filter($(this).attr("data-fieldname"),
  310. $(this).attr("data-value"));
  311. return false;
  312. })
  313. .attr("data-fieldname", opts.content)
  314. .attr("data-value", data[opts.content])
  315. .find("a").attr("href", "#");
  316. }
  317. else if(data[opts.content]) {
  318. $("<span>")
  319. .html(wn.format(data[opts.content], opts.df, null, data))
  320. .appendTo(parent.css({"overflow":"hidden"}))
  321. }
  322. // finally
  323. if(!$(parent).html()) {
  324. $("<span>-</span>").css({color:"#ccc"}).appendTo(parent);
  325. }
  326. // title
  327. if(!in_list(["avatar", "_user_tags", "check"], opts.content)) {
  328. if($(parent).attr("title")==undefined) {
  329. $(parent).attr("title", (opts.title || opts.content) + ": "
  330. + (data[opts.content] || "Not Set"))
  331. }
  332. $(parent).tooltip();
  333. }
  334. },
  335. show_hide_check_column: function() {
  336. if(!this.doclistview.can_delete) {
  337. this.columns = $.map(this.columns, function(v, i) { if(v.content!='check') return v });
  338. }
  339. },
  340. prepare_data: function(data) {
  341. if(data.modified)
  342. this.prepare_when(data, data.modified);
  343. // docstatus
  344. if(data.docstatus==0 || data.docstatus==null) {
  345. data.docstatus_icon = 'icon-check-empty';
  346. data.docstatus_title = wn._('Editable');
  347. } else if(data.docstatus==1) {
  348. data.docstatus_icon = 'icon-lock';
  349. data.docstatus_title = wn._('Submitted');
  350. } else if(data.docstatus==2) {
  351. data.docstatus_icon = 'icon-remove';
  352. data.docstatus_title = wn._('Cancelled');
  353. }
  354. // nulls as strings
  355. for(key in data) {
  356. if(data[key]==null) {
  357. data[key]='';
  358. }
  359. }
  360. // prepare data in settings
  361. if(this.settings.prepare_data)
  362. this.settings.prepare_data(data);
  363. },
  364. prepare_when: function(data, date_str) {
  365. if (!date_str) date_str = data.modified;
  366. // when
  367. data.when = (dateutil.str_to_user(date_str)).split(' ')[0];
  368. var diff = dateutil.get_diff(dateutil.get_today(), date_str.split(' ')[0]);
  369. if(diff==0) {
  370. data.when = dateutil.comment_when(date_str);
  371. }
  372. if(diff == 1) {
  373. data.when = wn._('Yesterday')
  374. }
  375. if(diff == 2) {
  376. data.when = wn._('2 days ago')
  377. }
  378. },
  379. render_bar_graph: function(parent, data, field, label) {
  380. var args = {
  381. percent: data[field],
  382. label: label
  383. }
  384. $(parent).append(repl('<span class="progress" style="width: 100%; float: left; margin: 5px 0px;"> \
  385. <span class="progress-bar" title="%(percent)s% %(label)s" \
  386. style="width: %(percent)s%;"></span>\
  387. </span>', args));
  388. },
  389. render_icon: function(parent, icon_class, label) {
  390. var icon_html = "<i class='%(icon_class)s' title='%(label)s'></i>";
  391. $(parent).append(repl(icon_html, {icon_class: icon_class, label: label || ''}));
  392. }
  393. });
  394. // embeddable
  395. wn.provide('wn.views.RecordListView');
  396. wn.views.RecordListView = wn.views.DocListView.extend({
  397. init: function(doctype, wrapper, ListView) {
  398. this.doctype = doctype;
  399. this.wrapper = wrapper;
  400. this.listview = new ListView(this, doctype);
  401. this.listview.parent = this;
  402. this.setup();
  403. },
  404. setup: function() {
  405. var me = this;
  406. me.page_length = 10;
  407. $(me.wrapper).empty();
  408. me.init_list();
  409. },
  410. get_args: function() {
  411. var args = this._super();
  412. $.each((this.default_filters || []), function(i, f) {
  413. args.filters.push(f);
  414. });
  415. args.docstatus = args.docstatus.concat((this.default_docstatus || []));
  416. return args;
  417. },
  418. });