From ac692473252992bafc3664dc6fb41c0b85d35e19 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 15 Dec 2016 14:48:43 +0530 Subject: [PATCH] [feature] checkboxes in grid #2451 --- frappe/model/mapper.py | 23 ++++++ frappe/public/js/frappe/form/grid.js | 76 ++++++++++++++++--- frappe/public/js/frappe/form/link_selector.js | 10 +-- .../js/frappe/form/templates/grid_body.html | 2 + frappe/public/js/frappe/model/create_new.js | 6 +- frappe/public/js/legacy/clientscriptAPI.js | 22 ++++++ frappe/tests/test_scheduler.py | 6 +- frappe/utils/scheduler.py | 8 +- 8 files changed, 131 insertions(+), 22 deletions(-) diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py index ff227ab174..e7c55fe78b 100644 --- a/frappe/model/mapper.py +++ b/frappe/model/mapper.py @@ -7,6 +7,22 @@ from frappe import _ from frappe.utils import cstr from frappe.model import default_fields +@frappe.whitelist() +def make_mapped_doc(method, source_name, selected_children=None): + '''Returns the mapped document calling the given mapper method. + Sets selected_children as flags for the `get_mapped_doc` method. + + Called from `open_mapped_doc` from create_new.js''' + method = frappe.get_attr(method) + + if method not in frappe.whitelisted: + raise frappe.PermissionError + + frappe.flags.selected_children = selected_children + + return method(source_name) + + def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None, postprocess=None, ignore_permissions=False, ignore_child_tables=False): @@ -51,6 +67,13 @@ def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None, if not table_map["condition"](source_d): continue + # if children are selected (checked from UI) for this table type, + # and this record is not in the selected children, then continue + if (frappe.flags.selected_children + and (df.fieldname in frappe.flags.selected_children) + and source_d.name not in frappe.flags.selected_children): + continue + target_child_doctype = table_map["doctype"] target_parentfield = target_doc.get_parentfield_of_doctype(target_child_doctype) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index 76dc3dee8e..fa79453f0d 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -58,10 +58,45 @@ frappe.ui.form.Grid = Class.extend({ this.custom_buttons = {}; this.grid_buttons = this.wrapper.find('.grid-buttons'); + this.remove_rows_button = this.grid_buttons.find('.grid-remove-rows') this.setup_allow_bulk_edit(); + this.setup_check(); }, + setup_check: function() { + var me = this; + this.wrapper.on('click', '.grid-row-check', function(e) { + $check = $(this); + if($check.parents('.grid-heading-row:first').length!==0) { + $check.parents('.form-grid:first').find('.grid-row-check').prop('checked', $check.prop('checked')); + } + me.refresh_remove_rows_button(); + }); + + this.remove_rows_button.on('click', function() { + me.get_selected().forEach(function(docname) { + me.grid_rows_by_docname[docname].remove(); + }); + setTimeout(function() { me.refresh_remove_rows_button(); }, 100); + }); + }, + refresh_remove_rows_button: function() { + this.remove_rows_button.toggleClass('hide', + this.wrapper.find('.grid-body .grid-row-check:checked:first').length ? false : true); + }, + get_selected: function() { + var selected = []; + var me = this; + this.wrapper.find('.grid-body .grid-row-check:checked').each(function() { + selected.push($(this).parents('.grid-row:first').attr('data-name')); + }); + return selected; + }, + refresh_checks: function() { + var show = this.is_editable() || this.frm.has_mapper(); + this.wrapper.find('.grid-row-check').toggle(show); + }, make_head: function() { // labels if(!this.header_row) { @@ -132,6 +167,7 @@ frappe.ui.form.Grid = Class.extend({ // toolbar this.setup_toolbar(); + this.refresh_checks(); // sortable if(this.is_sortable() && !this.sortable_setup_done) { @@ -143,6 +179,8 @@ frappe.ui.form.Grid = Class.extend({ this.last_docname = this.frm.docname; frappe.utils.scroll_to(_scroll_y); } + + this.refresh_remove_rows_button(); }, setup_toolbar: function() { if(this.is_editable()) { @@ -216,7 +254,6 @@ frappe.ui.form.Grid = Class.extend({ return; } - new Sortable($rows.get(0), { group: {name: 'row'}, handle: ".sortable-handle", @@ -545,6 +582,7 @@ frappe.ui.form.GridRow = Class.extend({ init: function(opts) { this.on_grid_fields_dict = {}; this.on_grid_fields = []; + this.row_check_html = ''; this.columns = {}; this.columns_list = []; $.extend(this, opts); @@ -552,9 +590,13 @@ frappe.ui.form.GridRow = Class.extend({ }, make: function() { var me = this; + this.wrapper = $('
').appendTo(this.parent).data("grid_row", this); this.row = $('
').appendTo(this.wrapper) - .on("click", function() { + .on("click", function(e) { + if($(e.target).hasClass('grid-row-check')) { + return; + } if(me.grid.allow_on_grid_editing() && me.grid.is_editable()) { // pass } else { @@ -563,6 +605,11 @@ frappe.ui.form.GridRow = Class.extend({ } }); + // no checkboxes if too small + if(this.is_too_small()) { + this.row_check_html = ''; + } + if(this.grid.template && !this.grid.meta.editable_grid) { this.render_template(); } else { @@ -582,7 +629,7 @@ frappe.ui.form.GridRow = Class.extend({ this.wrapper .attr('data-name', this.doc.name) .attr("data-idx", this.doc.idx) - .find(".row-index, .grid-form-row-index").html(this.doc.idx) + .find(".row-index span, .grid-form-row-index").html(this.doc.idx) } }, @@ -638,9 +685,9 @@ frappe.ui.form.GridRow = Class.extend({ if(this.doc) { if(!this.row_index) { this.row_index = $('
').appendTo(this.row); + margin-right: -20px;">'+this.row_check_html+' ').appendTo(this.row); } - this.row_index.html(this.doc.idx); + this.row_index.find('span').html(this.doc.idx); } this.row_display = $('
'+ @@ -657,11 +704,18 @@ frappe.ui.form.GridRow = Class.extend({ // index (1, 2, 3 etc) if(!this.row_index) { - this.row_index = $('
' + (this.doc ? this.doc.idx : " ")+ '
') + var txt = (this.doc ? this.doc.idx : " "); + this.row_index = $('
' + + this.row_check_html + + ' ' + txt + '
') .appendTo(this.row) - .on('click', function() { me.toggle_view(); }); + .on('click', function(e) { + if(!$(e.target).hasClass('grid-row-check')) { + me.toggle_view(); + } + }); } else { - this.row_index.html(this.doc ? this.doc.idx : " "); + this.row_index.find('span').html(txt); } this.setup_columns(); @@ -676,6 +730,10 @@ frappe.ui.form.GridRow = Class.extend({ this.row.toggleClass('editable-row', this.grid.is_editable()); }, + is_too_small: function() { + return this.row.width() < 400; + }, + add_open_form_button: function() { var me = this; if(this.doc) { @@ -686,7 +744,7 @@ frappe.ui.form.GridRow = Class.extend({ .appendTo($('
').appendTo(this.row)) .on('click', function() { me.toggle_view(); return false; }); - if(this.row.width() < 400) { + if(this.is_too_small()) { // narrow this.open_form_button.css({'margin-right': '-2px'}); } diff --git a/frappe/public/js/frappe/form/link_selector.js b/frappe/public/js/frappe/form/link_selector.js index f17a125b73..58f9ee2f74 100644 --- a/frappe/public/js/frappe/form/link_selector.js +++ b/frappe/public/js/frappe/form/link_selector.js @@ -99,11 +99,11 @@ frappe.ui.form.LinkSelector = Class.extend({ }) }) } else { - $('
' + __("No Results") - + (frappe.model.can_read(me.doctype) ? - ('. ' - + __("Make a new") + " " + __(me.doctype) + "") : '') - + '
').appendTo(parent).find(".new-doc").click(function() { + $('


' + __("No Results") + '' + + (frappe.model.can_create(me.doctype) ? + ('

' + + __("Make a new {0}", [__(me.doctype)]) + "") : '') + + '

').appendTo(parent).find(".new-doc").click(function() { me.target.new_doc(); }); } diff --git a/frappe/public/js/frappe/form/templates/grid_body.html b/frappe/public/js/frappe/form/templates/grid_body.html index 7a2adac38f..d74667d4df 100644 --- a/frappe/public/js/frappe/form/templates/grid_body.html +++ b/frappe/public/js/frappe/form/templates/grid_body.html @@ -7,6 +7,8 @@