Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

372 linhas
9.7 KiB

  1. // Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. //
  3. // MIT License (MIT)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a
  6. // copy of this software and associated documentation files (the "Software"),
  7. // to deal in the Software without restriction, including without limitation
  8. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. // and/or sell copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22. // new re-factored Listing object
  23. // removed rarely used functionality
  24. //
  25. // opts:
  26. // parent
  27. // method (method to call on server)
  28. // args (additional args to method)
  29. // get_args (method to return args as dict)
  30. // show_filters [false]
  31. // doctype
  32. // filter_fields (if given, this list is rendered, else built from doctype)
  33. // query or get_query (will be deprecated)
  34. // query_max
  35. // buttons_in_frame
  36. // no_result_message ("No result")
  37. // page_length (20)
  38. // hide_refresh (False)
  39. // no_toolbar
  40. // new_doctype
  41. // [function] render_row(parent, data)
  42. // [function] onrun
  43. // no_loading (no ajax indicator)
  44. wn.provide('wn.ui');
  45. wn.ui.Listing = Class.extend({
  46. init: function(opts) {
  47. this.opts = opts || {};
  48. this.page_length = 20;
  49. this.start = 0;
  50. this.data = [];
  51. if(opts) {
  52. this.make();
  53. }
  54. },
  55. prepare_opts: function() {
  56. if(this.opts.new_doctype) {
  57. if(wn.boot.profile.can_create.indexOf(this.opts.new_doctype)==-1) {
  58. this.opts.new_doctype = null;
  59. } else {
  60. this.opts.new_doctype = this.opts.new_doctype;
  61. }
  62. }
  63. if(!this.opts.no_result_message) {
  64. this.opts.no_result_message = wn._('Nothing to show');
  65. }
  66. this.opts._more = wn._("More");
  67. },
  68. make: function(opts) {
  69. if(opts) {
  70. this.opts = opts;
  71. }
  72. this.prepare_opts();
  73. $.extend(this, this.opts);
  74. $(this.parent).html(repl('\
  75. <div class="wnlist">\
  76. <h3 class="title hide">%(title)s</h3>\
  77. \
  78. <div class="list-filters" style="display: none;">\
  79. <div class="show_filters well" style="display: none;">\
  80. <div class="filter_area"></div>\
  81. <div>\
  82. <button class="btn btn-default btn-info search-btn">\
  83. <i class="icon-refresh icon-white"></i> \
  84. <span class="hidden-phone">Search</span></button>\
  85. <button class="btn btn-default add-filter-btn">\
  86. <i class="icon-plus"></i> \
  87. <span class="hidden-phone">Add Filter</span></button>\
  88. </div>\
  89. </div>\
  90. </div>\
  91. \
  92. <div style="margin-bottom:9px" class="list-toolbar-wrapper">\
  93. <div class="list-toolbar btn-group" style="display:inline-block; margin-right: 10px;">\
  94. </div>\
  95. <div style="display: none; width: 24px; margin-left: 4px">\
  96. <img src="lib/images/ui/button-load.gif" \
  97. class="img-load"/></div>\
  98. </div><div style="clear:both"></div>\
  99. \
  100. <div class="no-result" style="display: none;">\
  101. %(no_result_message)s\
  102. </div>\
  103. \
  104. <div class="result">\
  105. <div class="result-list"></div>\
  106. </div>\
  107. \
  108. <p class="paging-button" style="text-align: center;">\
  109. <button class="btn btn-default btn-more" style="display: none; margin: 15px 0px;">%(_more)s...</div>\
  110. </p>\
  111. </div>\
  112. ', this.opts));
  113. this.$w = $(this.parent).find('.wnlist');
  114. this.set_events();
  115. if(this.appframe) {
  116. this.$w.find('.list-toolbar-wrapper').toggle(false);
  117. }
  118. if(this.show_filters) {
  119. this.make_filters();
  120. }
  121. },
  122. add_button: function(label, click, icon) {
  123. if(this.appframe) {
  124. return this.appframe.add_button(label, click, icon)
  125. } else {
  126. $button = $('<button class="btn btn-default"></button>')
  127. .appendTo(this.$w.find('.list-toolbar'))
  128. .html((icon ? ("<i class='"+icon+"'></i> ") : "") + label)
  129. .click(click);
  130. return $button
  131. }
  132. },
  133. show_view: function($btn, $div, $btn_unsel, $div_unsel) {
  134. $btn_unsel.removeClass('btn-info');
  135. $btn_unsel.find('i').removeClass('icon-white');
  136. $div_unsel.toggle(false);
  137. $btn.addClass('btn-info');
  138. $btn.find('i').addClass('icon-white');
  139. $div.toggle(true);
  140. },
  141. set_events: function() {
  142. var me = this;
  143. // next page
  144. this.$w.find('.btn-more').click(function() {
  145. me.run({append: true });
  146. });
  147. // title
  148. if(this.title) {
  149. this.$w.find('h3').html(this.title).toggle(true);
  150. }
  151. // hide-refresh
  152. if(!(this.hide_refresh || this.no_refresh)) {
  153. this.add_button('', function() {
  154. me.run();
  155. }, 'icon-refresh');
  156. }
  157. // new
  158. if(this.new_doctype) {
  159. this.add_button(wn._('New') + ' ' + wn._(this.new_doctype), function() {
  160. (me.custom_new_doc || me.make_new_doc)(me.new_doctype);
  161. }, 'icon-plus');
  162. }
  163. // hide-filter
  164. if(me.show_filters) {
  165. this.add_button(wn._('Filter'), function() {
  166. me.filter_list.show_filters();
  167. }, 'icon-search').addClass('btn-filter');
  168. }
  169. if(me.no_toolbar || me.hide_toolbar) {
  170. me.$w.find('.list-toolbar-wrapper').toggle(false);
  171. }
  172. },
  173. make_new_doc: function(new_doctype) {
  174. new_doc(new_doctype);
  175. },
  176. make_filters: function() {
  177. this.filter_list = new wn.ui.FilterList({
  178. listobj: this,
  179. $parent: this.$w.find('.list-filters').toggle(true),
  180. doctype: this.doctype,
  181. filter_fields: this.filter_fields
  182. });
  183. },
  184. clear: function() {
  185. this.data = [];
  186. this.$w.find('.result-list').empty();
  187. this.$w.find('.result').toggle(true);
  188. this.$w.find('.no-result').toggle(false);
  189. this.start = 0;
  190. },
  191. run: function(more) {
  192. var me = this;
  193. if(!more) {
  194. this.start = 0;
  195. if(this.onreset) this.onreset();
  196. }
  197. if(!me.opts.no_loading)
  198. me.set_working(true);
  199. wn.call({
  200. method: this.opts.method || 'webnotes.widgets.query_builder.runquery',
  201. type: "GET",
  202. args: this.get_call_args(),
  203. callback: function(r) {
  204. if(!me.opts.no_loading)
  205. me.set_working(false);
  206. me.dirty = false;
  207. me.render_results(r);
  208. },
  209. no_spinner: this.opts.no_loading
  210. });
  211. },
  212. set_working: function(flag) {
  213. this.$w.find('.img-load').toggle(flag);
  214. },
  215. get_call_args: function() {
  216. // load query
  217. if(!this.method) {
  218. var query = this.get_query ? this.get_query() : this.query;
  219. query = this.add_limits(query);
  220. var args={
  221. query_max: this.query_max,
  222. as_dict: 1
  223. }
  224. args.simple_query = query;
  225. } else {
  226. var args = {
  227. limit_start: this.start,
  228. limit_page_length: this.page_length
  229. }
  230. }
  231. // append user-defined arguments
  232. if(this.args)
  233. $.extend(args, this.args)
  234. if(this.get_args) {
  235. $.extend(args, this.get_args());
  236. }
  237. return args;
  238. },
  239. render_results: function(r) {
  240. if(this.start===0) this.clear();
  241. this.$w.find('.btn-more').toggle(false);
  242. if(r.message) {
  243. r.values = this.get_values_from_response(r.message);
  244. }
  245. if(r.values && r.values.length) {
  246. this.data = this.data.concat(r.values);
  247. this.render_list(r.values);
  248. this.update_paging(r.values);
  249. } else {
  250. if(this.start===0) {
  251. this.$w.find('.result').toggle(false);
  252. var msg = this.get_no_result_message
  253. ? this.get_no_result_message()
  254. : (this.no_result_message
  255. ? this.no_result_message
  256. : wn._("Nothing to show"));
  257. this.$w.find('.no-result')
  258. .html(msg)
  259. .toggle(true);
  260. }
  261. }
  262. // callbacks
  263. if(this.onrun) this.onrun();
  264. if(this.callback) this.callback(r);
  265. },
  266. get_values_from_response: function(data) {
  267. // make dictionaries from keys and values
  268. if(data.keys) {
  269. var values = [];
  270. $.each(data.values, function(row_idx, row) {
  271. var new_row = {};
  272. $.each(data.keys, function(key_idx, key) {
  273. new_row[key] = row[key_idx];
  274. })
  275. values.push(new_row);
  276. });
  277. return values;
  278. } else {
  279. return data;
  280. }
  281. },
  282. render_list: function(values) {
  283. var m = Math.min(values.length, this.page_length);
  284. this.data = values;
  285. if(this.filter_list)
  286. this.filter_values = this.filter_list.get_filters();
  287. // render the rows
  288. for(var i=0; i < m; i++) {
  289. this.render_row(this.add_row(), values[i], this, i);
  290. }
  291. },
  292. update_paging: function(values) {
  293. if(values.length >= this.page_length) {
  294. this.$w.find('.btn-more').toggle(true);
  295. this.start += this.page_length;
  296. }
  297. },
  298. add_row: function() {
  299. return $('<div class="list-row">').appendTo(this.$w.find('.result-list')).get(0);
  300. },
  301. refresh: function() {
  302. this.run();
  303. },
  304. add_limits: function(query) {
  305. query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
  306. return query
  307. },
  308. set_filter: function(fieldname, label) {
  309. var filter = this.filter_list.get_filter(fieldname);
  310. //this.filter_list.show_filters(true);
  311. if(filter) {
  312. var v = filter.field.get_parsed_value();
  313. if(v.indexOf(label)!=-1) {
  314. // already set
  315. return false;
  316. } else {
  317. // second filter set for this field
  318. if(fieldname=='_user_tags') {
  319. // and for tags
  320. this.filter_list.add_filter(this.doctype, fieldname,
  321. '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,
  332. 'like', '%' + label);
  333. } else {
  334. this.filter_list.add_filter(this.doctype, fieldname, '=', label);
  335. }
  336. }
  337. }
  338. });