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.

doclistview.js 11 KiB

13 years ago
13 years ago
13 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
13 years ago
11 years ago
11 years ago
11 years ago
11 years ago
13 years ago
11 years ago
13 years ago
13 years ago
12 years ago
11 years ago
13 years ago
13 years ago
13 years ago
12 years ago
11 years ago
12 years ago
11 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. });