/** * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out */ openerp.base.list.editable = function (openerp) { var KEY_RETURN = 13, KEY_ESCAPE = 27; // editability status of list rows openerp.base.ListView.prototype.defaults.editable = null; var old_init = openerp.base.ListView.prototype.init, old_actual_search = openerp.base.ListView.prototype.do_actual_search, old_add_record = openerp.base.ListView.prototype.do_add_record, old_on_loaded = openerp.base.ListView.prototype.on_loaded; // TODO: not sure second @lends on existing item is correct, to check _.extend(openerp.base.ListView.prototype, /** @lends openerp.base.ListView# */{ init: function () { var self = this; old_init.apply(this, arguments); $(this.groups).bind({ 'edit': function (e, id, dataset) { self.do_edit(dataset.index, id, dataset); }, 'saved': function () { if (self.groups.get_selection().length) { return; } self.compute_aggregates(); } }) }, /** * Handles the activation of a record in editable mode (making a record * editable), called *after* the record has become editable. * * The default behavior is to setup the listview's dataset to match * whatever dataset was provided by the editing List * * @param {Number} index index of the record in the dataset * @param {Object} id identifier of the record being edited * @param {openerp.base.DataSet} dataset dataset in which the record is available */ do_edit: function (index, id, dataset) { _.extend(this.dataset, dataset); }, /** * Sets editability status for the list, based on defaults, view * architecture and the provided flag, if any. * * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom". */ set_editable: function (force) { // If ``force``, set editability to bottom // otherwise rely on view default // view' @editable is handled separately as we have not yet // fetched and processed the view at this point. this.options.editable = ( (force && "bottom") || this.defaults.editable); }, /** * Replace do_actual_search to handle editability process */ do_actual_search: function (results) { this.set_editable(results.context['set_editable']); old_actual_search.call(this, results); }, /** * Replace do_add_record to handle editability (and adding new record * as an editable row at the top or bottom of the list) */ do_add_record: function () { if (this.options.editable) { this.groups.new_record(); } else { old_add_record.call(this); } }, on_loaded: function (data, grouped) { // tree/@editable takes priority on everything else if present. this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable; return old_on_loaded.call(this, data, grouped); } }); _.extend(openerp.base.ListView.Groups.prototype, /** @lends openerp.base.ListView.Groups# */{ passtrough_events: openerp.base.ListView.Groups.prototype.passtrough_events + " edit saved", new_record: function () { // TODO: handle multiple children this.children[null].new_record(); } }); var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked; _.extend(openerp.base.ListView.List.prototype, /** @lends openerp.base.ListView.List */{ row_clicked: function (event) { if (!this.options.editable) { return old_list_row_clicked.call(this, event); } this.edit_record(); }, /** * Checks if a record is being edited, and if so cancels it */ cancel_pending_edition: function () { var self = this, cancelled = $.Deferred(); if (!this.edition) { cancelled.resolve(); return cancelled.promise(); } if (this.edition_index !== null) { this.reload_record(this.edition_index, true).then(function () { cancelled.resolve(); }); } else { cancelled.resolve(); } cancelled.then(function () { self.edition_form.stop(); self.edition_form.$element.remove(); delete self.edition_form; delete self.edition_index; delete self.edition; }); return cancelled.promise(); }, /** * Adapts this list's view description to be suitable to the inner form view of a row being edited. * * @returns {Object} fields_view_get's view section suitable for putting into form view of editable rows. */ get_form_fields_view: function () { // deep copy of view var view = $.extend(true, {}, this.group.view.fields_view); _(view.arch.children).each(function (widget) { widget.attrs.nolabel = true; if (widget.tag === 'button') { delete widget.attrs.string; } }); view.arch.attrs.col = 2 * view.arch.children.length; return view; }, render_row_as_form: function (row) { var self = this; this.cancel_pending_edition().then(function () { var $new_row = $('