25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

372 lines
11 KiB

  1. // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. wn.provide('wn.views.doclistview');
  4. wn.provide('wn.doclistviews');
  5. wn.views.ListFactory = wn.views.Factory.extend({
  6. make: function(route) {
  7. var me = this;
  8. wn.model.with_doctype(route[1], function() {
  9. if(locals["DocType"][route[1]].issingle) {
  10. wn.set_re_route("Form", route[1]);
  11. } else {
  12. new wn.views.DocListView({
  13. doctype: route[1],
  14. page: me.make_page(true)
  15. });
  16. }
  17. });
  18. }
  19. });
  20. $(document).on("save", function(event, doc) {
  21. var list_page = "List/" + doc.doctype;
  22. if(wn.pages[list_page]) {
  23. if(wn.pages[list_page].doclistview)
  24. wn.pages[list_page].doclistview.dirty = true;
  25. }
  26. })
  27. wn.views.DocListView = wn.ui.Listing.extend({
  28. init: function(opts) {
  29. $.extend(this, opts)
  30. this.label = wn._(this.doctype);
  31. this.dirty = true;
  32. this.tags_shown = false;
  33. this.label = (this.label.toLowerCase().substr(-4) == 'list') ?
  34. wn._(this.label) : (wn._(this.label) + ' ' + wn._('List'));
  35. this.make_page();
  36. this.setup();
  37. var me = this;
  38. $(this.page).on("show", function() {
  39. me.refresh();
  40. });
  41. // refresh on init
  42. me.refresh();
  43. },
  44. make_page: function() {
  45. var me = this;
  46. this.page.doclistview = this;
  47. this.$page = $(this.page).css({"min-height": "400px"});
  48. $('<div class="wnlist-area" style="margin-bottom: 25px;">\
  49. <div class="help">'+wn._('Loading')+'...</div></div>')
  50. .appendTo(this.$page.find(".layout-main-section"));
  51. $('<div class="show-docstatus hide side-panel">\
  52. <h5 class="text-muted">Show</h5>\
  53. <div class="side-panel-body">\
  54. <div class="text-muted small"><input data-docstatus="0" type="checkbox" \
  55. checked="checked" /> '+wn._('Drafts')+'</div>\
  56. <div class="text-muted small"><input data-docstatus="1" type="checkbox" \
  57. checked="checked" /> '+wn._('Submitted')+'</div>\
  58. <div class="text-muted small"><input data-docstatus="2" type="checkbox" \
  59. /> '+wn._('Cancelled')+'</div></div>\
  60. </div>')
  61. .appendTo(this.$page.find(".layout-side-section"));
  62. this.$page.find(".layout-main-section")
  63. .css({"border-right":"1px solid #d7d7d7"})
  64. .parent().css({"margin-top":"-15px"});
  65. this.appframe = this.page.appframe;
  66. var module = locals.DocType[this.doctype].module;
  67. this.appframe.set_title(wn._(this.doctype) + " " + wn._("List"));
  68. this.appframe.add_module_icon(module, this.doctype, null, true);
  69. this.appframe.set_views_for(this.doctype, "list");
  70. },
  71. setup: function() {
  72. this.can_delete = wn.model.can_delete(this.doctype);
  73. this.meta = locals.DocType[this.doctype];
  74. this.$page.find('.wnlist-area').empty(),
  75. this.setup_listview();
  76. this.setup_docstatus_filter();
  77. this.init_list(false);
  78. this.init_stats();
  79. this.init_minbar();
  80. this.show_match_help();
  81. if(this.listview.settings.onload) {
  82. this.listview.settings.onload(this);
  83. }
  84. this.make_help();
  85. this.$page.find(".show_filters").css({"padding":"15px", "margin":"0px -15px"});
  86. var me = this;
  87. // this.$w.on("render-complete", function() {
  88. // me.set_sidebar_height();
  89. // });
  90. },
  91. set_sidebar_height: function() {
  92. var h_main = this.$page.find(".layout-main-section").height();
  93. var h_side = this.$page.find(".layout-side-section").height();
  94. if(h_side > h_main)
  95. this.$page.find(".layout-main-section").css({"min-height": h_side});
  96. },
  97. show_match_help: function() {
  98. var me = this;
  99. var match_rules = wn.perm.get_match_rules(this.doctype);
  100. var perm = wn.perm.get_perm(this.doctype);
  101. if(keys(match_rules).length) {
  102. var match_text = []
  103. $.each(match_rules, function(key, values) {
  104. if(values.length==0) {
  105. match_text.push(wn._(key) + wn._(" is not set"));
  106. } else if(values.length) {
  107. match_text.push(wn._(key) + " = " + wn.utils.comma_or(values));
  108. }
  109. });
  110. if(perm[0].restricted) {
  111. match_text.push(wn._("Or Created By") + " = " + user);
  112. }
  113. wn.utils.set_footnote(this, this.$page.find(".layout-main-section"),
  114. "<p>" + wn._("Showing only for") + ":</p><ul>"
  115. + $.map(match_text, function(txt) { return "<li>"+txt+"</li>" }).join("")) + "</ul>";
  116. $(this.footnote_area).css({"margin-top":"0px", "margin-bottom":"20px"});
  117. }
  118. },
  119. make_help: function() {
  120. // Help
  121. if(this.meta.description) {
  122. this.appframe.add_help_button(this.meta.description);
  123. }
  124. },
  125. setup_docstatus_filter: function() {
  126. var me = this;
  127. this.can_submit = $.map(locals.DocPerm || [], function(d) {
  128. if(d.parent==me.meta.name && d.submit) return 1
  129. else return null;
  130. }).length;
  131. if(this.can_submit) {
  132. this.$page.find('.show-docstatus').removeClass('hide');
  133. this.$page.find('.show-docstatus input').click(function() {
  134. me.run();
  135. })
  136. }
  137. },
  138. setup_listview: function() {
  139. this.listview = wn.views.get_listview(this.doctype, this);
  140. this.wrapper = this.$page.find('.wnlist-area');
  141. this.page_length = 20;
  142. this.allow_delete = true;
  143. },
  144. init_list: function(auto_run) {
  145. var me = this;
  146. // init list
  147. this.make({
  148. method: 'webnotes.widgets.reportview.get',
  149. get_args: this.get_args,
  150. parent: this.wrapper,
  151. freeze: true,
  152. start: 0,
  153. page_length: this.page_length,
  154. show_filters: true,
  155. show_grid: true,
  156. new_doctype: this.doctype,
  157. allow_delete: this.allow_delete,
  158. no_result_message: this.make_no_result(),
  159. custom_new_doc: me.listview.make_new_doc || undefined,
  160. });
  161. // make_new_doc can be overridden so that default values can be prefilled
  162. // for example - communication list in customer
  163. $(this.wrapper).on("click", 'button[list_view_doc="'+me.doctype+'"]', function(){
  164. (me.listview.make_new_doc || me.make_new_doc).apply(me, [me.doctype]);
  165. });
  166. if((auto_run !== false) && (auto_run !== 0))
  167. this.refresh();
  168. },
  169. refresh: function() {
  170. var me = this;
  171. if(wn.route_options) {
  172. me.set_route_options();
  173. } else if(me.dirty) {
  174. me.run();
  175. } else {
  176. if(new Date() - (me.last_updated_on || 0) > 30000) {
  177. // older than 5 mins, refresh
  178. me.run();
  179. }
  180. }
  181. },
  182. set_route_options: function() {
  183. var me = this;
  184. me.filter_list.clear_filters();
  185. $.each(wn.route_options, function(key, value) {
  186. me.filter_list.add_filter(me.doctype, key, "=", value);
  187. });
  188. wn.route_options = null;
  189. me.run();
  190. },
  191. run: function(more) {
  192. // set filter from route
  193. var route = wn.get_route();
  194. var me = this;
  195. if(route[2]) {
  196. $.each(wn.utils.get_args_dict_from_url(route[2]), function(key, val) {
  197. me.set_filter(key, val, true);
  198. });
  199. }
  200. this.last_updated_on = new Date();
  201. this._super(more);
  202. },
  203. make_no_result: function() {
  204. var new_button = wn.boot.profile.can_create.indexOf(this.doctype)!=-1
  205. ? ('<hr><p><button class="btn btn-primary" \
  206. list_view_doc="%(doctype)s">'+
  207. wn._('Make a new') + ' %(doctype_label)s</button></p>')
  208. : '';
  209. var no_result_message = repl('<div class="well" style="margin-top: 20px;">\
  210. <p>' + wn._("No") + ' %(doctype_label)s ' + wn._("found") + '</p>' + new_button + '</div>', {
  211. doctype_label: wn._(this.doctype),
  212. doctype: this.doctype,
  213. });
  214. return no_result_message;
  215. },
  216. render_row: function(row, data) {
  217. data.doctype = this.doctype;
  218. this.listview.render(row, data, this);
  219. },
  220. get_args: function() {
  221. var docstatus_list = this.can_submit ? $.map(this.$page.find('.show-docstatus :checked'),
  222. function(inp) {
  223. return $(inp).attr('data-docstatus');
  224. }) : []
  225. var args = {
  226. doctype: this.doctype,
  227. fields: this.listview.fields,
  228. filters: this.filter_list.get_filters(),
  229. docstatus: docstatus_list,
  230. order_by: this.listview.order_by || undefined,
  231. group_by: this.listview.group_by || undefined,
  232. }
  233. // apply default filters, if specified for a listing
  234. $.each((this.listview.default_filters || []), function(i, f) {
  235. args.filters.push(f);
  236. });
  237. return args;
  238. },
  239. init_minbar: function() {
  240. var me = this;
  241. this.appframe.add_icon_btn("2", 'icon-tag', wn._('Show Tags'), function() { me.toggle_tags(); });
  242. this.wrapper.on("click", ".list-tag-preview", function() { me.toggle_tags(); });
  243. if(this.can_delete || this.listview.settings.selectable) {
  244. this.appframe.add_icon_btn("2", 'icon-remove', wn._('Delete'), function() { me.delete_items(); });
  245. this.appframe.add_icon_btn("2", 'icon-ok', wn._('Select All'), function() {
  246. me.$page.find('.list-delete').prop("checked",
  247. me.$page.find('.list-delete:checked').length ? false : true);
  248. });
  249. }
  250. if(wn.model.can_import(this.doctype)) {
  251. this.appframe.add_icon_btn("2", "icon-upload", wn._("Import"), function() {
  252. wn.set_route("data-import-tool", {
  253. doctype: me.doctype
  254. })
  255. });
  256. }
  257. if(in_list(user_roles, "System Manager")) {
  258. this.appframe.add_icon_btn("2", "icon-glass", wn._("Customize"), function() {
  259. wn.set_route("Form", "Customize Form", {
  260. doctype: me.doctype
  261. })
  262. });
  263. }
  264. },
  265. toggle_tags: function() {
  266. if(this.tags_shown) {
  267. $(".tag-row").addClass("hide");
  268. this.tags_shown=false;
  269. } else {
  270. $(".tag-row").removeClass("hide");
  271. this.tags_shown=true;
  272. }
  273. },
  274. get_checked_items: function() {
  275. return $.map(this.$page.find('.list-delete:checked'), function(e) {
  276. return $(e).data('data');
  277. });
  278. },
  279. delete_items: function() {
  280. var me = this;
  281. var dl = this.get_checked_items();
  282. if(!dl.length)
  283. return;
  284. wn.confirm(wn._('This is permanent action and you cannot undo. Continue?'),
  285. function() {
  286. me.set_working(true);
  287. return wn.call({
  288. method: 'webnotes.widgets.reportview.delete_items',
  289. args: {
  290. items: $.map(dl, function(d, i) { return d.name }),
  291. doctype: me.doctype
  292. },
  293. callback: function() {
  294. me.set_working(false);
  295. me.dirty = true;
  296. me.refresh();
  297. }
  298. })
  299. }
  300. );
  301. },
  302. init_stats: function() {
  303. var me = this;
  304. this.sidebar_stats = new wn.views.SidebarStats({
  305. doctype: this.doctype,
  306. stats: this.listview.stats,
  307. parent: this.$page.find('.layout-side-section'),
  308. set_filter: function(fieldname, label) {
  309. me.set_filter(fieldname, label);
  310. },
  311. doclistview: this
  312. })
  313. },
  314. set_filter: function(fieldname, label, no_run) {
  315. var filter = this.filter_list.get_filter(fieldname);
  316. if(filter) {
  317. var v = cstr(filter.field.get_parsed_value());
  318. if(v.indexOf(label)!=-1) {
  319. // already set
  320. return false;
  321. } else {
  322. // second filter set for this field
  323. if(fieldname=='_user_tags') {
  324. // and for tags
  325. this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
  326. } else {
  327. // or for rest using "in"
  328. filter.set_values(this.doctype, fieldname, 'in', v + ', ' + label);
  329. }
  330. }
  331. } else {
  332. // no filter for this item,
  333. // setup one
  334. if(fieldname=='_user_tags') {
  335. this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
  336. } else {
  337. this.filter_list.add_filter(this.doctype, fieldname, '=', label);
  338. }
  339. }
  340. if(!no_run)
  341. this.run();
  342. }
  343. });