Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

353 rader
10 KiB

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