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.
 
 
 
 
 
 

902 linhas
25 KiB

  1. // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. // MIT License. See license.txt
  3. frappe.provide('frappe.views.doclistview');
  4. frappe.provide('frappe.listviews');
  5. cur_list = null;
  6. frappe.views.ListFactory = frappe.views.Factory.extend({
  7. make: function(route) {
  8. var me = this,
  9. doctype = route[1];
  10. frappe.model.with_doctype(doctype, function() {
  11. if(locals["DocType"][doctype].issingle) {
  12. frappe.set_re_route("Form", doctype);
  13. } else {
  14. if(!frappe.views.doclistview[doctype]) {
  15. frappe.views.doclistview[doctype] = new frappe.views.DocListView({
  16. doctype: doctype,
  17. parent: me.make_page(true, "List/" + doctype)
  18. });
  19. } else {
  20. frappe.container.change_to(frappe.views.doclistview[doctype].page_name);
  21. }
  22. me.set_cur_list();
  23. }
  24. });
  25. },
  26. show: function() {
  27. this.set_module_breadcrumb();
  28. this._super();
  29. this.set_cur_list();
  30. cur_list && cur_list.refresh();
  31. },
  32. set_module_breadcrumb: function() {
  33. if(frappe.route_history.length > 1) {
  34. var prev_route = frappe.route_history[frappe.route_history.length-2];
  35. if(prev_route[0]==="modules") {
  36. var doctype = frappe.get_route()[1],
  37. module = prev_route[1];
  38. if(frappe.module_links[module] && in_list(frappe.module_links[module], doctype)) {
  39. // save the last page from the breadcrumb was accessed
  40. frappe.breadcrumbs.set_doctype_module(doctype, module);
  41. }
  42. }
  43. }
  44. },
  45. set_cur_list: function() {
  46. var route = frappe.get_route();
  47. cur_list = frappe.container.page && frappe.container.page.doclistview;
  48. if(cur_list && cur_list.doctype!==route[1]) {
  49. // changing...
  50. cur_list = null;
  51. }
  52. }
  53. });
  54. $(document).on("save", function(event, doc) {
  55. frappe.views.set_list_as_dirty(doc.doctype);
  56. });
  57. frappe.views.set_list_as_dirty = function(doctype) {
  58. var list_page = "List/" + doctype;
  59. if(frappe.pages[list_page]) {
  60. if(frappe.pages[list_page].doclistview) {
  61. if(frappe.pages[list_page].doclistview.dirty) {
  62. // already refreshing...
  63. return;
  64. }
  65. frappe.pages[list_page].doclistview.dirty = true;
  66. }
  67. }
  68. var route = frappe.get_route();
  69. if(route[0]==="List" && route[1]===doctype) {
  70. setTimeout(function() {
  71. frappe.pages[list_page].doclistview.refresh();
  72. }, 100);
  73. }
  74. }
  75. frappe.views.DocListView = frappe.ui.Listing.extend({
  76. init: function(opts) {
  77. $.extend(this, opts);
  78. if(!frappe.model.can_read(this.doctype)) {
  79. frappe.show_not_permitted(frappe.get_route_str());
  80. return;
  81. };
  82. this.label = __(this.doctype);
  83. this.page_name = "List/" + this.doctype;
  84. this.dirty = true;
  85. this.tags_shown = false;
  86. this.label = (this.label.toLowerCase().substr(-4) == 'list') ?
  87. __(this.label) : (__(this.label) + ' ' + __('List'));
  88. this.make_page();
  89. this.setup();
  90. // refresh on init
  91. this.refresh();
  92. },
  93. make_page: function() {
  94. var me = this;
  95. this.parent.doclistview = this;
  96. this.page = this.parent.page;
  97. this.$page = $(this.parent).css({"min-height": "400px"});
  98. $('<div class="frappe-list-area"></div>')
  99. .appendTo(this.page.main);
  100. this.page.main.addClass("listview-main-section");
  101. var module = locals.DocType[this.doctype].module;
  102. this.page.set_title(__(this.doctype));
  103. frappe.breadcrumbs.add(module, this.doctype);
  104. },
  105. setup: function() {
  106. var me = this;
  107. this.can_delete = frappe.model.can_delete(this.doctype);
  108. this.meta = locals.DocType[this.doctype];
  109. this.$page.find('.frappe-list-area').empty(),
  110. this.init_list_settings();
  111. this.setup_listview();
  112. this.init_list(false);
  113. this.init_menu();
  114. this.show_match_help();
  115. this.init_listview();
  116. this.setup_filterable();
  117. this.init_filters();
  118. this.init_sort_selector();
  119. },
  120. init_headers: function() {
  121. this.page.main.find(".list-headers").empty();
  122. this.header = this.current_view === 'List' ? "list_item_main_head": "image_view_item_main_head";
  123. var main = frappe.render_template(this.header, {
  124. columns: this.listview.columns,
  125. right_column: this.listview.settings.right_column,
  126. _checkbox: ((frappe.model.can_delete(this.doctype) || this.listview.settings.selectable)
  127. && !this.listview.no_delete)
  128. });
  129. this.list_header = $(frappe.render_template("list_item_row_head", { main:main, list:this.listview }))
  130. .appendTo(this.page.main.find(".list-headers"));
  131. this.init_like();
  132. this.init_select_all();
  133. },
  134. init_listview: function() {
  135. if(this.listview.settings.onload) {
  136. this.listview.settings.onload(this);
  137. }
  138. },
  139. set_sidebar_height: function() {
  140. var h_main = this.page.sidebar.height();
  141. var h_side = this.$page.find(".layout-side-section").height();
  142. if(h_side > h_main)
  143. this.$page.find(".layout-main-section").css({"min-height": h_side});
  144. },
  145. setup_filterable: function() {
  146. var me = this;
  147. this.$page.on("click", ".filterable", function(e) {
  148. var filters = $(this).attr("data-filter").split("|");
  149. var added = false;
  150. $.each(filters, function(i, f) {
  151. f = f.split(",");
  152. if(f[2]==="Today") {
  153. f[2] = frappe.datetime.get_today();
  154. } else if(f[2]=="User") {
  155. f[2] = user;
  156. }
  157. var new_filter = me.filter_list.add_filter(me.doctype, f[0], f[1], f.slice(2).join(","));
  158. if (new_filter) {
  159. // set it to true if atleast 1 filter is added
  160. added = true;
  161. }
  162. });
  163. if(added) {
  164. me.refresh(true);
  165. }
  166. });
  167. this.$page.find(".result-list").on("click", ".list-row-left", function(e) {
  168. // don't open in case of checkbox, like, filterable
  169. if ((e.target.className || "").indexOf("filterable")!==-1
  170. || (e.target.className || "").indexOf("octicon-heart")!==-1
  171. || e.target.type==="checkbox") {
  172. return;
  173. }
  174. var link = $(this).parent().find("a.list-id").get(0);
  175. window.location.href = link.href;
  176. return false;
  177. });
  178. },
  179. init_filters: function() {
  180. var me = this;
  181. var set_filters = function(filters) {
  182. $.each(filters, function(i, f) {
  183. if(f.length===3) {
  184. f = [me.doctype, f[0], f[1], f[2]]
  185. }
  186. me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
  187. });
  188. }
  189. if(this.list_settings.filters) {
  190. set_filters(this.list_settings.filters);
  191. } else if(this.listview.settings.filters) {
  192. set_filters(this.listview.settings.filters);
  193. }
  194. },
  195. init_sort_selector: function() {
  196. var args = null;
  197. var me = this;
  198. if(this.listview.sort_selector) {
  199. args = this.listview.sort_selector;
  200. }
  201. if(this.list_settings.order_by) {
  202. // last saved settings
  203. var order_by = this.list_settings.order_by
  204. if(order_by.indexOf('`.`')!==-1) {
  205. // scrub table name (separted by dot), like `tabTime Log`.`modified` desc`
  206. order_by = order_by.split('.')[1];
  207. }
  208. parts = order_by.split(' ');
  209. if(parts.length===2) {
  210. var fieldname = strip(parts[0], '`');
  211. args = {
  212. sort_by: fieldname,
  213. sort_order: parts[1]
  214. }
  215. }
  216. }
  217. this.sort_selector = new frappe.ui.SortSelector({
  218. parent: this.wrapper.find('.list-filters'),
  219. doctype: this.doctype,
  220. args: args,
  221. change: function() {
  222. me.run();
  223. }
  224. });
  225. },
  226. show_match_help: function() {
  227. var me = this;
  228. var match_rules_list = frappe.perm.get_match_rules(this.doctype);
  229. var perm = frappe.perm.get_perm(this.doctype);
  230. if(match_rules_list.length) {
  231. frappe.utils.set_footnote(this, this.$page.find(".layout-main-section"),
  232. frappe.render_template("list_permission_footer", {condition_list: match_rules_list}));
  233. $(this.footnote_area).css({"margin-top":"0px"});
  234. }
  235. },
  236. setup_listview: function() {
  237. this.listview = frappe.views.get_listview(this.doctype, this);
  238. this.wrapper = this.$page.find('.frappe-list-area');
  239. this.page_length = this.list_settings.limit || 20;
  240. this.allow_delete = true;
  241. },
  242. init_list: function(auto_run) {
  243. var me = this;
  244. // init list
  245. this.make({
  246. method: 'frappe.desk.reportview.get',
  247. save_list_settings: true,
  248. get_args: this.get_args,
  249. parent: this.wrapper,
  250. freeze: true,
  251. start: 0,
  252. page_length: this.page_length,
  253. show_filters: true,
  254. show_grid: true,
  255. new_doctype: this.doctype,
  256. allow_delete: this.allow_delete,
  257. no_result_message: this.make_no_result(),
  258. custom_new_doc: me.listview.make_new_doc || undefined,
  259. });
  260. // make_new_doc can be overridden so that default values can be prefilled
  261. // for example - communication list in customer
  262. if(this.listview.settings.list_view_doc) {
  263. this.listview.settings.list_view_doc(this);
  264. }
  265. else{
  266. $(this.wrapper).on("click", 'button[list_view_doc="'+me.doctype+'"]', function(){
  267. (me.listview.make_new_doc || me.make_new_doc).apply(me, [me.doctype]);
  268. });
  269. }
  270. if((auto_run !== false) && (auto_run !== 0))
  271. this.refresh();
  272. },
  273. refresh: function(dirty) {
  274. if(dirty!==undefined) this.dirty = dirty;
  275. this.refresh_sidebar();
  276. // if view has changed, re-render header
  277. if(this.current_view != this.list_sidebar.current_view) {
  278. this.current_view = this.list_sidebar.current_view;
  279. this.init_headers();
  280. this.dirty = true;
  281. }
  282. if(this.listview.settings.refresh) {
  283. this.listview.settings.refresh(this);
  284. }
  285. this.set_filters_before_run();
  286. if(this.dirty) {
  287. this.run();
  288. } else {
  289. if(new Date() - (this.last_updated_on || 0) > 30000) {
  290. // older than 5 mins, refresh
  291. this.run();
  292. }
  293. }
  294. },
  295. set_filters_before_run: function() {
  296. // set filters from frappe.route_options
  297. // before switching pages, frappe.route_options can have pre-set filters
  298. // for the list view
  299. var me = this;
  300. if(frappe.route_options) {
  301. this.set_filters_from_route_options();
  302. this.dirty = true;
  303. } else if(this.list_settings && this.list_settings.filters
  304. && this.list_settings.updated_on != this.list_settings_updated_on) {
  305. // update remembered list settings
  306. this.filter_list.clear_filters();
  307. this.list_settings.filters.forEach(function(f) {
  308. me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
  309. });
  310. this.dirty = true;
  311. }
  312. },
  313. run: function(more) {
  314. // set filter from route
  315. var me = this;
  316. if(this.fresh && !more) {
  317. return;
  318. }
  319. if(this.listview.settings.before_run) {
  320. this.listview.settings.before_run(this);
  321. }
  322. if(!this.listview.settings.use_route) {
  323. var route = frappe.get_route();
  324. if(route[2] && !in_list(['Image', 'Gantt'], route[2])) {
  325. $.each(frappe.utils.get_args_dict_from_url(route[2]), function(key, val) {
  326. me.set_filter(key, val, true);
  327. });
  328. }
  329. }
  330. this.list_header.find(".list-liked-by-me")
  331. .toggleClass("text-extra-muted not-liked", !this.is_star_filtered());
  332. this.last_updated_on = new Date();
  333. this.dirty = false;
  334. // set a fresh so that multiple refreshes do not happen
  335. // at the same time. This is true when deleting.
  336. // AJAX response will try to refresh and list_update notification
  337. // via async will also try to update.
  338. // It is not possible to guess which will reach first
  339. // (most probably async will) but this is a forced way
  340. // to prevent instant refreshes on mutilple triggers
  341. // in a loosly coupled way.
  342. this.fresh = true;
  343. setTimeout(function() {
  344. me.fresh = false;
  345. }, 1000);
  346. this._super(more);
  347. if(this.listview.settings.post_render) {
  348. this.listview.settings.post_render(this);
  349. }
  350. this.list_settings_updated_on = this.list_settings.updated_on;
  351. },
  352. make_no_result: function() {
  353. var new_button = frappe.boot.user.can_create.indexOf(this.doctype)!=-1
  354. ? ('<p><button class="btn btn-primary btn-sm" \
  355. list_view_doc="' + this.doctype + '">'+
  356. __('Make a new {0}', [__(this.doctype)]) + '</button></p>')
  357. : '';
  358. var no_result_message = '<div class="msg-box no-border" style="margin: 100px 0px;">\
  359. <p>' + __("No {0} found", [__(this.doctype)]) + '</p>' + new_button + '</div>';
  360. return no_result_message;
  361. },
  362. render_rows: function(values) {
  363. this['render_rows_' + this.current_view](values);
  364. },
  365. render_rows_Image: function(values) {
  366. var cols = values.slice();
  367. while (cols.length) {
  368. row = this.add_row(cols[0]);
  369. $("<div class='row image-view-marker'></div>").appendTo(row);
  370. $(row).addClass('no-hover');
  371. this.render_image_view_row(row, cols.splice(0, 4));
  372. }
  373. this.render_image_gallery();
  374. },
  375. render_rows_List: function(values) {
  376. var m = Math.min(values.length, this.page_length);
  377. for(var i=0; i < m; i++) {
  378. this.render_row(this.add_row(values[i]), values[i], this, i);
  379. }
  380. },
  381. render_rows_Gantt: function(values) {
  382. var gantt_area = $('<svg height="400" width="6000"></svg>')
  383. .appendTo(this.wrapper.find('.result-list').css("overflow", "scroll"));
  384. var id = frappe.dom.set_unique_id(gantt_area);
  385. var me = this;
  386. var field_map = frappe.views.calendar[this.doctype].field_map;
  387. var tasks = values.map(function(item) {
  388. return {
  389. start: item[field_map.start],
  390. end: item[field_map.end],
  391. name: item[field_map.title],
  392. id: item[field_map.id],
  393. doctype: me.doctype,
  394. progress: item.progress,
  395. dependent: item.depends_on_tasks || ""
  396. };
  397. });
  398. frappe.require(["assets/frappe/js/lib/snap.svg-min.js", "assets/frappe/css/gantt.css"], function() {
  399. me.gantt = new Gantt({
  400. parent_selector: '#' + id,
  401. tasks: tasks,
  402. date_format: "YYYY-MM-DD",
  403. bar: {
  404. height: 20
  405. },
  406. events: {
  407. bar_on_click: function (task) {
  408. frappe.set_route('Form', task.doctype, task.id);
  409. },
  410. bar_on_date_change: function(task, start, end) {
  411. update_field(task.id, field_map.start, start.format("YYYY-MM-DD"), function() {
  412. update_field(task.id, field_map.end, end.format("YYYY-MM-DD"), function() {
  413. show_alert({message:__("Saved"), indicator:'green'}, 1);
  414. });
  415. });
  416. },
  417. bar_on_progress_change: function(task, progress) {
  418. update_field(task.id, 'progress', progress, function() {
  419. show_alert({message:__("Saved"), indicator:'green'}, 1);
  420. });
  421. },
  422. on_viewmode_change: function(mode) {
  423. me.list_settings.view_mode = mode;
  424. }
  425. }
  426. });
  427. me.gantt.render();
  428. var view_modes = me.gantt.get_view_modes() || [];
  429. var dropdown = "<div class='dropdown pull-right'>" +
  430. "<a class='text-muted dropdown-toggle' data-toggle='dropdown'>" +
  431. "<span class='dropdown-text'>"+__('Day')+"</span><i class='caret'></i></a>" +
  432. "<ul class='dropdown-menu'></ul>" +
  433. "</div>";
  434. // view modes (for translation) __("Day"), __("Week"), __("Month"),
  435. //__("Half Day"), __("Quarter Day")
  436. var dropdown_list = "";
  437. view_modes.forEach(function(view_mode) {
  438. dropdown_list += "<li>" +
  439. "<a class='option' data-value='"+view_mode+"'>" +
  440. __(view_mode) + "</a></li>";
  441. })
  442. var $dropdown = $(dropdown)
  443. $dropdown.find(".dropdown-menu")
  444. .append(dropdown_list);
  445. me.$page.find(".list-row-right").css("margin-top", 0).html($dropdown)
  446. $dropdown.on("click", ".option", function() {
  447. var mode = $(this).data('value');
  448. me.gantt.set_view_mode(mode)
  449. $dropdown.find(".dropdown-text").text(mode);
  450. })
  451. });
  452. function update_field(id, fieldname, value, callback) {
  453. frappe.call({
  454. method: "frappe.client.set_value",
  455. freeze: false,
  456. args: {
  457. doctype: me.doctype,
  458. name: id,
  459. fieldname: fieldname,
  460. value: value
  461. },
  462. callback: function(r) {
  463. callback();
  464. }
  465. });
  466. }
  467. },
  468. render_row: function(row, data) {
  469. data.doctype = this.doctype;
  470. this.listview.render(row, data, this);
  471. },
  472. render_image_view_row: function(row, data) {
  473. for (var i = 0; i < data.length; i++) {
  474. data[i].doctype = this.doctype;
  475. this.listview.render(row, data[i], this)
  476. }
  477. },
  478. get_args: function() {
  479. var args = {
  480. doctype: this.doctype,
  481. fields: this.listview.fields,
  482. filters: this.filter_list.get_filters(),
  483. order_by: this.listview.order_by || undefined,
  484. group_by: this.listview.group_by || undefined,
  485. with_comment_count: true
  486. }
  487. // apply default filters, if specified for a listing
  488. $.each((this.listview.default_filters || this.listview.settings.default_filters || []), function(i, f) {
  489. args.filters.push(f);
  490. });
  491. args.order_by = '`tab' + this.doctype + '`.`' + this.sort_selector.sort_by + '` ' + this.sort_selector.sort_order;
  492. return args;
  493. },
  494. assigned_to_me: function() {
  495. this.filter_list.add_filter(this.doctype, "_assign", 'like', '%' + user + '%');
  496. this.run();
  497. },
  498. liked_by_me: function() {
  499. this.filter_list.add_filter(this.doctype, "_liked_by", 'like', '%' + user + '%');
  500. this.run();
  501. },
  502. remove_liked_by_me: function() {
  503. this.filter_list.get_filter("_liked_by").remove();
  504. },
  505. is_star_filtered: function() {
  506. return this.filter_list.filter_exists(this.doctype, "_liked_by", 'like', '%' + user + '%');
  507. },
  508. init_menu: function() {
  509. var me = this;
  510. this.$page.on("click", ".list-tag-preview", function() { me.toggle_tags(); });
  511. this.page.set_secondary_action(__("Refresh"), function() {
  512. me.dirty = true;
  513. me.refresh();
  514. }, "octicon octicon-sync");
  515. this.page.btn_secondary.addClass("hidden-xs");
  516. this.page.add_menu_item(__("Refresh"), function() {
  517. me.dirty = true;
  518. me.refresh();
  519. }, "octicon octicon-sync").addClass("visible-xs");
  520. if(frappe.model.can_import(this.doctype)) {
  521. this.page.add_menu_item(__("Import"), function() {
  522. frappe.set_route("data-import-tool", {
  523. doctype: me.doctype
  524. });
  525. }, true);
  526. }
  527. if(frappe.model.can_set_user_permissions(this.doctype)) {
  528. this.page.add_menu_item(__("User Permissions Manager"), function() {
  529. frappe.route_options = {
  530. doctype: me.doctype
  531. };
  532. frappe.set_route("user-permissions");
  533. }, true);
  534. }
  535. if(in_list(user_roles, "System Manager")) {
  536. this.page.add_menu_item(__("Role Permissions Manager"), function() {
  537. frappe.route_options = {
  538. doctype: me.doctype
  539. };
  540. frappe.set_route("permission-manager");
  541. }, true);
  542. this.page.add_menu_item(__("Customize"), function() {
  543. frappe.set_route("Form", "Customize Form", {
  544. doc_type: me.doctype
  545. })
  546. }, true);
  547. }
  548. this.make_bulk_assignment();
  549. this.make_bulk_printing();
  550. // add to desktop
  551. this.page.add_menu_item(__("Add to Desktop"), function() {
  552. frappe.add_to_desktop(me.doctype, me.doctype);
  553. }, true);
  554. if (in_list(user_roles, "System Manager") && frappe.boot.developer_mode===1) {
  555. // edit doctype
  556. this.page.add_menu_item(__("Edit DocType"), function() {
  557. frappe.set_route('Form', 'DocType', me.doctype);
  558. }, true);
  559. }
  560. },
  561. make_bulk_assignment: function() {
  562. var me = this;
  563. //bulk assignment
  564. me.page.add_menu_item(__("Assign To"), function(){
  565. docname = [];
  566. $.each(me.get_checked_items(), function(i, doc){
  567. docname.push(doc.name);
  568. })
  569. if(docname.length >= 1){
  570. me.dialog = frappe.ui.to_do_dialog({
  571. obj: me,
  572. method: 'frappe.desk.form.assign_to.add_multiple',
  573. doctype: me.doctype,
  574. docname: docname,
  575. bulk_assign: true,
  576. re_assign: true,
  577. callback: function(){
  578. me.dirty = true;
  579. me.refresh();
  580. }
  581. });
  582. me.dialog.clear();
  583. me.dialog.show();
  584. }
  585. else{
  586. frappe.msgprint(__("Select records for assignment"))
  587. }
  588. }, true)
  589. },
  590. make_bulk_printing: function() {
  591. var me = this;
  592. var print_settings = frappe.model.get_doc(":Print Settings", "Print Settings")
  593. var allow_print_for_draft = cint(print_settings.allow_print_for_draft)
  594. var is_submittable = frappe.model.is_submittable(me.doctype)
  595. var allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled)
  596. //bulk priting
  597. me.page.add_menu_item(__("Print"), function(){
  598. var no_print = false
  599. docname = [];
  600. $.each(me.get_checked_items(), function(i, doc){
  601. if(!is_submittable || doc.docstatus == 1 ||
  602. (allow_print_for_cancelled && doc.docstatus == 2)||
  603. (allow_print_for_draft && doc.docstatus == 0)||
  604. in_list(user_roles, "Administrator"))
  605. docname.push(doc.name);
  606. else
  607. no_print = true
  608. })
  609. if(no_print == true){
  610. frappe.msgprint("You selected Draft or Cancelled documents")
  611. }
  612. if(docname.length >= 1){
  613. var dialog = new frappe.ui.Dialog({
  614. title: "Print Documents",
  615. fields: [
  616. {"fieldtype": "Check", "label": __("With Letterhead"), "fieldname": "with_letterhead"},
  617. {"fieldtype": "Select", "label": __("Print Format"), "fieldname": "print_sel"},
  618. ]
  619. });
  620. dialog.set_primary_action(__('Print'), function() {
  621. args = dialog.get_values();
  622. if(!args) return;
  623. var default_print_format = locals.DocType[me.doctype].default_print_format;
  624. with_letterhead = args.with_letterhead ? 1 : 0;
  625. print_format = args.print_sel ? args.print_sel:default_print_format;
  626. var json_string = JSON.stringify(docname);
  627. var w = window.open("/api/method/frappe.utils.print_format.download_multi_pdf?"
  628. +"doctype="+encodeURIComponent(me.doctype)
  629. +"&name="+encodeURIComponent(json_string)
  630. +"&format="+encodeURIComponent(print_format)
  631. +"&no_letterhead="+(with_letterhead ? "0" : "1"));
  632. if(!w) {
  633. msgprint(__("Please enable pop-ups")); return;
  634. }
  635. })
  636. print_formats = frappe.meta.get_print_formats(me.doctype);
  637. dialog.fields_dict.print_sel.$input.empty().add_options(print_formats);
  638. dialog.show();
  639. }
  640. else{
  641. frappe.msgprint(__("Select records for assignment"))
  642. }
  643. }, true);
  644. },
  645. init_like: function() {
  646. var me = this;
  647. this.$page.find(".result-list").on("click", ".like-action", frappe.ui.click_toggle_like);
  648. this.list_header.find(".list-liked-by-me").on("click", function() {
  649. if (me.is_star_filtered()) {
  650. me.remove_liked_by_me();
  651. } else {
  652. me.liked_by_me();
  653. }
  654. });
  655. if (!frappe.dom.is_touchscreen()) {
  656. frappe.ui.setup_like_popover(this.$page.find(".result-list"), ".liked-by");
  657. }
  658. },
  659. init_select_all: function() {
  660. var me = this;
  661. if(this.can_delete || this.listview.settings.selectable) {
  662. this.list_header.find(".list-select-all").on("click", function() {
  663. me.$page.find('.list-delete').prop("checked", $(this).prop("checked"));
  664. me.toggle_delete();
  665. });
  666. this.$page.on("click", ".list-delete", function(event) {
  667. me.toggle_delete();
  668. // multi-select using shift key
  669. var $this = $(this);
  670. if (event.shiftKey && $this.prop("checked")) {
  671. var $end_row = $this.parents(".list-row");
  672. var $start_row = $end_row.prevAll(".list-row")
  673. .find(".list-delete:checked").last().parents(".list-row");
  674. if ($start_row) {
  675. $start_row.nextUntil($end_row).find(".list-delete").prop("checked", true);
  676. }
  677. }
  678. });
  679. // after delete, hide delete button
  680. this.wrapper.on("render-complete", function() {
  681. me.toggle_delete();
  682. });
  683. }
  684. },
  685. toggle_delete: function() {
  686. var me = this;
  687. if (this.$page.find(".list-delete:checked").length) {
  688. this.page.set_primary_action(__("Delete"), function() { me.delete_items() },
  689. "octicon octicon-trashcan");
  690. this.page.btn_primary.addClass("btn-danger");
  691. } else {
  692. this.page.btn_primary.removeClass("btn-danger");
  693. this.set_primary_action();
  694. }
  695. },
  696. toggle_tags: function() {
  697. if(this.tags_shown) {
  698. $(".tag-row").addClass("hide");
  699. this.tags_shown=false;
  700. } else {
  701. $(".tag-row").removeClass("hide");
  702. this.tags_shown=true;
  703. }
  704. },
  705. get_checked_items: function() {
  706. var me = this;
  707. return $.map(this.$page.find('.list-delete:checked'), function(e) {
  708. if(me.current_view==='List'){
  709. return $(e).parents(".list-row:first").data('data');
  710. }
  711. else{
  712. return $(e).parents(".image-view:first").data('data');
  713. }
  714. });
  715. },
  716. delete_items: function() {
  717. var me = this;
  718. var dl = this.get_checked_items();
  719. if(!dl.length)
  720. return;
  721. frappe.confirm(__('Delete permanently?'),
  722. function() {
  723. me.set_working(true);
  724. return frappe.call({
  725. method: 'frappe.desk.reportview.delete_items',
  726. freeze: true,
  727. args: {
  728. items: $.map(dl, function(d, i) { return d.name }),
  729. doctype: me.doctype
  730. },
  731. callback: function() {
  732. me.$page.find('.list-select-all').prop("checked", false);
  733. frappe.utils.play_sound("delete");
  734. me.set_working(false);
  735. me.dirty = true;
  736. me.refresh();
  737. }
  738. })
  739. }
  740. );
  741. },
  742. refresh_sidebar: function() {
  743. var me = this;
  744. this.list_sidebar = new frappe.views.ListSidebar({
  745. doctype: this.doctype,
  746. stats: this.listview.stats,
  747. parent: this.$page.find('.layout-side-section'),
  748. set_filter: function(fieldname, label) {
  749. me.set_filter(fieldname, label);
  750. },
  751. page: this.page,
  752. doclistview: this
  753. })
  754. },
  755. set_filter: function(fieldname, label, no_run) {
  756. var filter = this.filter_list.get_filter(fieldname);
  757. if(filter) {
  758. var v = cstr(filter.field.get_parsed_value());
  759. if(v.indexOf(label)!=-1) {
  760. // already set
  761. return false;
  762. } else {
  763. // second filter set for this field
  764. if(fieldname=='_user_tags' || fieldname=="_liked_by") {
  765. // and for tags
  766. this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
  767. } else {
  768. // or for rest using "in"
  769. filter.set_values(this.doctype, fieldname, 'in', v + ', ' + label);
  770. }
  771. }
  772. } else {
  773. // no filter for this item,
  774. // setup one
  775. if(fieldname=='_user_tags' || fieldname=="_liked_by") {
  776. this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
  777. } else {
  778. this.filter_list.add_filter(this.doctype, fieldname, '=', label);
  779. }
  780. }
  781. if(!no_run)
  782. this.run();
  783. },
  784. call_for_selected_items: function(method, args) {
  785. var me = this;
  786. args.names = $.map(this.get_checked_items(), function(d) { return d.name; });
  787. frappe.call({
  788. method: method,
  789. args: args,
  790. freeze: true,
  791. callback: function(r) {
  792. if(!r.exc) {
  793. me.list_header.find(".list-select-all").prop("checked", false);
  794. me.refresh();
  795. }
  796. }
  797. });
  798. }
  799. });