diff --git a/src/sao.js b/src/sao.js index faaf577184..c37284fe67 100644 --- a/src/sao.js +++ b/src/sao.js @@ -163,6 +163,24 @@ var Sao = {}; 'domain': domain }); form.view_prm.done(function() { + var view = form.screen.current_view; + view.table.find('th').hide(); + var display = view.display; + var select_row = function(event_) { + this.tree.select_changed(this.record); + this.tree.switch_(this.path); + }; + var set_select_row = function(row) { + row.select_row = select_row; + row.rows.forEach(set_select_row); + }; + view.display = function() { + display.call(this); + view.table.find('td:nth-child(1)').hide(); + // TODO remove when shortcuts is implemented + view.table.find('td:nth-child(3)').hide(); + view.rows.forEach(set_select_row); + }; jQuery('#menu').append( form.screen.screen_container.content_box.detach()); }); diff --git a/src/view.js b/src/view.js index ce7f0e7489..9e74bcb9e3 100644 --- a/src/view.js +++ b/src/view.js @@ -79,9 +79,17 @@ var thead = jQuery(''); this.table.append(thead); var tr = jQuery(''); + var th = jQuery(''); + this.selection = jQuery('', { + 'type': 'checkbox', + 'class': 'selection' + }); + this.selection.change(this.selection_changed.bind(this)); + th.append(this.selection); + tr.append(th); thead.append(tr); this.columns.forEach(function(column) { - var th = jQuery('', { + th = jQuery('', { 'text': column.attributes.string }); tr.append(th); @@ -190,12 +198,13 @@ }.bind(this)); }, display: function() { + var selected = this.selected_records(); this.rows = []; this.tbody.empty(); var add_row = function(record, pos, group) { var tree_row = new Sao.View.Tree.Row(this, record, pos); this.rows.push(tree_row); - tree_row.display(); + tree_row.display(selected); }; this.screen.group.forEach(add_row.bind(this)); }, @@ -209,18 +218,47 @@ }, selected_records: function() { var records = []; - this.rows.forEach(function(row) { + var add_record = function(row) { if (row.is_selected()) { records.push(row.record); } - }); + row.rows.forEach(add_record); + }; + this.rows.forEach(add_record); return records; + }, + selection_changed: function() { + var value = this.selection.prop('checked'); + var set_checked = function(row) { + row.set_selection(value); + row.rows.forEach(set_checked); + }; + this.rows.forEach(set_checked); + if (value && this.rows[0]) { + this.select_changed(this.rows[0].record); + } else { + this.select_changed(null); + } + }, + update_selection: function() { + var selected_records = this.selected_records(); + this.selection.prop('indeterminate', false); + if (jQuery.isEmptyObject(selected_records)) { + this.selection.prop('checked', false); + } else if (selected_records.length == this.tbody.children().length) { + this.selection.prop('checked', true); + } else { + this.selection.prop('indeterminate', true); + // Set checked to go first unchecked after first click + this.selection.prop('checked', true); + } } }); Sao.View.Tree.Row = Sao.class_(Object, { init: function(tree, record, pos, parent) { this.tree = tree; + this.rows = []; this.record = record; this.children_field = tree.children_field; this.expander = null; @@ -232,18 +270,20 @@ path.push(pos); this.path = path.join('.'); this.el = jQuery(''); - this.el.click(this.select_row.bind(this)); - var switch_ = function() { - this.el.addClass('ui-state-highlight'); - this.tree.select_changed(this.record); - this.tree.switch_(path); - }; - this.el.dblclick(switch_.bind(this)); + var td = jQuery(''); + this.el.append(td); + this.selection = jQuery('', { + 'type': 'checkbox', + 'class': 'selection' + }); + this.selection.change(this.selection_changed.bind(this)); + td.append(this.selection); }, is_expanded: function() { return (this.path in this.tree.expanded); }, - display: function() { + display: function(selected) { + selected = selected || []; var depth = this.path.split('.').length; var update_expander = function() { if (jQuery.isEmptyObject( @@ -253,8 +293,14 @@ this.expander_icon.hide(); } }; + // Use this handler to allow customization of select_row for the + // menu + var click_handler = function(event_) { + this.select_row(event_); + }; for (var i = 0; i < this.tree.columns.length; i++) { var td = jQuery(''); + td.click(click_handler.bind(this)); if ((i === 0) && this.children_field) { var expanded = 'ui-icon-plus'; if (this.is_expanded()) { @@ -290,13 +336,15 @@ } this.el.append(td); } + this.set_selection(~selected.indexOf(this.record)); this.tree.tbody.append(this.el); if (this.is_expanded()) { var add_children = function() { var add_row = function(record, pos, group) { var tree_row = new Sao.View.Tree.Row(this.tree, record, pos, this); - tree_row.display(); + this.rows.push(tree_row); + tree_row.display(selected); }; var children = this.record.field_get_client(children_field); children.forEach(add_row.bind(this)); @@ -323,16 +371,38 @@ } this.tree.display(); }, - select_row: function() { - this.el.toggleClass('ui-state-highlight'); - if (this.is_selected()) { - this.tree.select_changed(this.record); - } else { - this.tree.select_changed(null); + select_row: function(event_) { + if (!event_.ctrlKey) { + this.tree.rows.forEach(function(row) { + if (row != this) { + row.set_selection(false); + } + }.bind(this)); + this.selection_changed(); + if (this.is_selected()) { + this.tree.switch_(this.path); + return; + } } + this.set_selection(!this.is_selected()); + this.selection_changed(); }, is_selected: function() { - return this.el.hasClass('ui-state-highlight'); + return this.selection.prop('checked'); + }, + set_selection: function(value) { + this.selection.prop('checked', value); + }, + selection_changed: function() { + if (this.is_selected()) { + this.el.addClass('ui-state-highlight'); + this.tree.select_changed(this.record); + } else { + this.el.removeClass('ui-state-highlight'); + this.tree.select_changed( + this.tree.selected_records()[0] || null); + } + this.tree.update_selection(); } });