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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. });