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

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