<commit_before>/**
 * handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
 * @namespace
 */
openerp.web.list_editable = function (instance) {
    var KEY_RETURN = 13,
        KEY_ESCAPE = 27;
    var QWeb = instance.web.qweb;

    // editability status of list rows
    instance.web.ListView.prototype.defaults.editable = null;

    // TODO: not sure second @lends on existing item is correct, to check
    instance.web.ListView.include(/** @lends instance.web.ListView# */{
        init: function () {
            var self = this;
            this._super.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.configure_pager(self.dataset);
                    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 {instance.web.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 = true || (
                    ! this.options.read_only && ((force && "bottom") || this.defaults.editable));
        },
        /**
         * Replace do_search to handle editability process
         */
        do_search: function(domain, context, group_by) {
            this.set_editable(context['set_editable']);
            this._super.apply(this, arguments);
        },
        /**
         * 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.$element.find('table:first').show();
                this.$element.find('.oe_view_nocontent').remove();
                this.groups.new_record();
            } else {
                this._super();
            }
        },
        on_loaded: function (data, grouped) {
            var self = this, form_ready = $.when();
            // tree/@editable takes priority on everything else if present.
            this.options.editable = ! this.options.read_only && (data.arch.attrs.editable || this.options.editable);
            var result = this._super(data, grouped);
            if (this.options.editable || true) {
                // TODO: [Return], [Esc] events
                this.form = new instance.web.FormView(this, this.dataset, false, {
                    initial_mode: 'edit',
                    $buttons: $(),
                    $pager: $()
                });
                this.form.embedded_view = this.view_to_form_view();
                form_ready = this.form.prependTo(this.$element).then(function () {
                    self.form.do_hide();
                });
            }

            return $.when(result, form_ready);
        },
        /**
         * Ensures the editable list is saved (saves any pending edition if
         * needed, or tries to)
         *
         * Returns a deferred to the end of the saving.
         *
         * @returns {$.Deferred}
         */
        ensure_saved: function () {
            return this.groups.ensure_saved();
        },
        view_to_form_view: function () {
            var view = $.extend(true, {}, this.fields_view);
            view.arch.tag = 'form';
            _.extend(view.arch.attrs, {
                'class': 'oe_form_container',
                version: '7.0'
            });
            _(view.arch.children).each(function (widget) {
                var modifiers = JSON.parse(widget.attrs.modifiers || '{}');
                widget.attrs.nolabel = true;
                if (modifiers['tree_invisible'] || widget.tag === 'button') {
                    modifiers.invisible = true;
                }
                widget.attrs.modifiers = JSON.stringify(modifiers);
            });
            return view;
        },
        /**
         * Set up the edition of a record of the list view "inline"
         *
         * @param {Number} id id of the record to edit, null for new record
         * @param {Number} index index of the record to edit in the dataset, null for new record
         * @param {Object} cells map of field names to the DOM elements used to display these fields for the record being edited
         */
        edit_record: function (id, index, cells) {
            // TODO: save previous edition if any
            var self = this;
            var record = this.records.get(id);
            var e = {
                id: id,
                record: record,
                cancel: false
            };
            this.trigger('edit:before', e);
            if (e.cancel) {
                return;
            }
            return this.form.on_record_loaded(record.attributes).pipe(function () {
                return self.form.do_show({reload: false});
            }).then(function () {
                // TODO: automatic focus of ?first field
                // TODO: [Save] button
                // TODO: save on action button?
                _(cells).each(function (cell, field_name) {
                    var $cell = $(cell);
                    var position = $cell.position();
                    var field = self.form.fields[field_name];

                    // FIXME: this is shit. Is it possible to prefilter?
                    if (field.get('effective_readonly')) {
                        // Readonly fields can just remain the list's, form's
                        // usually don't have backgrounds &al
                        field.$element.hide();
                        return;
                    }
                    field.$element.show().css({
                        top: position.top,
                        left: position.left,
                        width: $cell.outerWidth(),
                        minHeight: $cell.outerHeight()
                    });
                });
                self.trigger('edit:after', record, self.form)
            });

        }
    });

    instance.web.ListView.Groups.include(/** @lends instance.web.ListView.Groups# */{
        passtrough_events: instance.web.ListView.Groups.prototype.passtrough_events + " edit saved",
        new_record: function () {
            // TODO: handle multiple children<commit_msg>[IMP] automatically focus first field of edited row<commit_after>/**
 * handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
 * @namespace
 */
openerp.web.list_editable = function (instance) {
    var KEY_RETURN = 13,
        KEY_ESCAPE = 27;
    var QWeb = instance.web.qweb;

    // editability status of list rows
    instance.web.ListView.prototype.defaults.editable = null;

    // TODO: not sure second @lends on existing item is correct, to check
    instance.web.ListView.include(/** @lends instance.web.ListView# */{
        init: function () {
            var self = this;
            this._super.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.configure_pager(self.dataset);
                    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 {instance.web.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 = true || (
                    ! this.options.read_only && ((force && "bottom") || this.defaults.editable));
        },
        /**
         * Replace do_search to handle editability process
         */
        do_search: function(domain, context, group_by) {
            this.set_editable(context['set_editable']);
            this._super.apply(this, arguments);
        },
        /**
         * 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.$element.find('table:first').show();
                this.$element.find('.oe_view_nocontent').remove();
                this.groups.new_record();
            } else {
                this._super();
            }
        },
        on_loaded: function (data, grouped) {
            var self = this, form_ready = $.when();
            // tree/@editable takes priority on everything else if present.
            this.options.editable = ! this.options.read_only && (data.arch.attrs.editable || this.options.editable);
            var result = this._super(data, grouped);
            if (this.options.editable || true) {
                // TODO: [Return], [Esc] events
                this.form = new instance.web.FormView(this, this.dataset, false, {
                    initial_mode: 'edit',
                    $buttons: $(),
                    $pager: $()
                });
                this.form.embedded_view = this.view_to_form_view();
                form_ready = this.form.prependTo(this.$element).then(function () {
                    self.form.do_hide();
                });
            }

            return $.when(result, form_ready);
        },
        /**
         * Ensures the editable list is saved (saves any pending edition if
         * needed, or tries to)
         *
         * Returns a deferred to the end of the saving.
         *
         * @returns {$.Deferred}
         */
        ensure_saved: function () {
            return this.groups.ensure_saved();
        },
        view_to_form_view: function () {
            var view = $.extend(true, {}, this.fields_view);
            view.arch.tag = 'form';
            _.extend(view.arch.attrs, {
                'class': 'oe_form_container',
                version: '7.0'
            });
            _(view.arch.children).each(function (widget) {
                var modifiers = JSON.parse(widget.attrs.modifiers || '{}');
                widget.attrs.nolabel = true;
                if (modifiers['tree_invisible'] || widget.tag === 'button') {
                    modifiers.invisible = true;
                }
                widget.attrs.modifiers = JSON.stringify(modifiers);
            });
            return view;
        },
        /**
         * Set up the edition of a record of the list view "inline"
         *
         * @param {Number} id id of the record to edit, null for new record
         * @param {Number} index index of the record to edit in the dataset, null for new record
         * @param {Object} cells map of field names to the DOM elements used to display these fields for the record being edited
         */
        edit_record: function (id, index, cells) {
            // TODO: save previous edition if any
            var self = this;
            var record = this.records.get(id);
            var e = {
                id: id,
                record: record,
                cancel: false
            };
            this.trigger('edit:before', e);
            if (e.cancel) {
                return;
            }
            return this.form.on_record_loaded(record.attributes).pipe(function () {
                return self.form.do_show({reload: false});
            }).then(function () {
                // TODO: [Save] button
                // TODO: save on action button?
                _(cells).each(function (cell, field_name) {
                    var $cell = $(cell);
                    var position = $cell.position();
                    var field = self.form.fields[field_name];

                    // FIXME: this is shit. Is it possible to prefilter?
                    if (field.get('effective_readonly')) {
                        // Readonly fields can just remain the list's, form's
                        // usually don't have backgrounds &al
                        field.$element.hide();
                        return;
                    }
                    field.$element.show().css({
                        top: position.top,
                        left: position.left,
                        width: $cell.outerWidth(),
                        minHeight: $cell.outerHeight()
                    });
                });
                // TODO: actually focus clicked field (if editable)
                self.form.fields[self.form.fields_order[0]].focus();
                self.trigger('edit:after', record, self.form)
            });

        }
    });

    instance.web.ListView.Groups.include(/** @lends instance.web.ListView.Groups# */{
        passtrough_events: instance.web.ListView.Groups.prototype.passtrough_events + " edit saved",
        new_record: function () {
            // TODO: handle multiple children
{'fraction_non_alphanumeric': 0.10615946757144722, 'fraction_numerical': 0.0008482317630170951, 'mean_word_length': 1.4701047542304593, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2485694', 'n_tokens_mistral': 3909, 'n_tokens_neox': 3724, 'n_words': 1112}