選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

394 行
11 KiB

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