GitHub PullRequestReviewCommentEvent at 2014-12-16 13:14:04
Repository: odoo
Actor: Gorash
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/odoo/odoo/pulls/comments/21896038","id":21896038,"diff_hunk":"@@ -0,0 +1,988 @@\n+(function () {\n+    'use strict';\n+\n+    var website = openerp.website;\n+    var _t = openerp._t;\n+    var ValidOption = false;\n+\n+    var removeWizard = function() {\n+        this.wizard.remove();\n+        if(this.DefFormPopUp.state() == 'pending') this.DefFormPopUp.reject();\n+    };\n+\n+    var getModel = function(model_field) {\n+\n+        var self   = this;\n+        var def    = $.Deferred();\n+        var form   = this.$target.closest('form');\n+\n+        if(!model_field && !form.data('model')) return def.reject();\n+\n+\n+        new openerp.Model(openerp.website.session,\"website.form\")\n+            .call(\"search_read\", [[['model_id', '=', form.data('model')]],['model_name', 'model_id', 'metadata_field_id']], {context: website.get_context()})\n+            .then(function(options_list) {\n+                console.log('elements', options_list);\n+                form.attr('data-model-name', options_list[0].model_id[1]);\n+                form.attr('data-default-field', options_list[0].metadata_field_id[1]);\n+            });\n+\n+        if(model_field == form.data('model') && !form.data('fields') && form.data('not-lock'))  return def.resolve();\n+\n+        form.data('not-lock',0);\n+        form.data('model', model_field);\n+        form.data('fields', {all:{},required:{}});\n+        new openerp.Model(openerp.website.session,\"website.form\")\n+        .call(\"get_authorized_fields\", [form.data('model')], {context: website.get_context()}).then(function(data) {\n+            var i = 0;\n+            var j = 0;\n+\n+            $.each(data, function(n, val) {\n+                var sel = val.selection || null;\n+                var rel = val.relation  || null;\n+                if(!form.data('fields')[val.type]) form.data('fields')[val.type] = {};\n+                form.data('fields')[val.type][n] = {name: n, label : val.string,relation : rel,selection : sel, type: val.type, required: val.required, help: val.help};\n+                form.data('fields').all[n] = form.data('fields')[val.type][n];\n+                if(val.required) form.data('fields').required[j++] = n;\n+            });\n+\n+            self.notLock = 1;\n+            def.resolve();\n+    \n+        }).fail(function() {\n+            self.notLock = 1;\n+            def.reject();\n+        });\n+        return def;\n+\n+    };\n+\n+    website.add_template_file('/website_form_builder/static/src/xml/website.form.editor.wizard.template.xml');\n+\n+\n+        //------------------------------//\n+        //      Option Editor           //\n+        //------------------------------//\n+        // Manage an editable table     //\n+        // With events to edit options  //\n+        // for one2many and many2many   //\n+        // fields                       //\n+        //------------------------------//\n+\n+    website.snippet.editFormFieldOptionEditor = openerp.Class.extend({\n+\n+        table: null,\n+        lock: null,\n+\n+        init: function(parent) {\n+            this.parent = parent;\n+            this.j = 3;\n+        },\n+        //Enable the widget with parameters : \n+        // wizard : wizard dom pointer\n+        // target: form field that need to be edit by the option editor\n+        // get : function needed to exctract data from the form field\n+        \n+        enable: function(wizard,target,get) {\n+            this.table = wizard.find('table');\n+            this.loadData(wizard,target,get);\n+            this.offAddField();\n+            this.onAddField();\n+        },\n+        //check all checkboxes\n+        checkAll: function(self) {\n+            return function() {\n+                var allBoxes = self.table.find('input');\n+                allBoxes.prop('checked',$(this).is(':checked'));\n+            };\n+        },\n+        //check number of checkbox checked to fix main checkbox\n+        checkAllStates: function(self) {\n+            return function() {\n+                var i=0,j=0;\n+                var checkAllBox  = self.table.find('th input');\n+                self.checked = !self.checked;\n+                self.table.find('input.delete').each(function(a,elem) {\n+                    if($(elem).is(':checked')) i++;\n+                    j++;\n+                });\n+                console.log(i,j);\n+                checkAllBox.prop(\"indeterminate\", false);\n+                if(i == j)      checkAllBox.prop('checked', true);\n+                else if(!i)     checkAllBox.prop('checked', false);\n+                else            checkAllBox.prop(\"indeterminate\", true);\n+            };\n+        },\n+        //enable events on the option editor to add or remove line\n+        onAddField: function() {\n+            var self = this;\n+            self.table.find('.last .option-label').attr('tabindex', this.j ++);\n+            self.table.find('.last .option-value').attr('tabindex', this.j ++);\n+            self.table.find('.last .option-label')  .on('focus', self.tabEvent);\n+            self.table.find('.last .option-value')  .on('focus', _.bind(self.tabEventWithCopy, this));\n+            self.table.find('td')                   .on('keyup', self.deleteIfEmpty);\n+            self.table.find('.last .option-value')  .on('keydown', self.addField(false));\n+            self.table.find('.o_form-editor-add')   .on('click',self.addField(true));\n+        },\n+        //disable events\n+        offAddField: function() {\n+            var self = this;\n+            self.table.find('.last .option-value')  .off('keydown');\n+            self.table.find('.last .option-value')  .on('focus', self.tabEvent);\n+            self.table.find('.o_form-editor-add')   .off('click');\n+            self.table.find('td')                   .off('td');\n+        },\n+        //check if the line is empty before delete it\n+        deleteIfEmpty : function (e) {\n+            var parent = $(this).parent();\n+            var prev,label,value;\n+            var p_label = parent.find('.option-label');\n+            var p_value = parent.find('.option-value');\n+            \n+            if(!p_label.html().length && !p_value.html().length) {\n+                    if(parent.hasClass('last')) {\n+                        prev = parent.prev();\n+                        label = prev.find('.option-label').html();\n+                        value = prev.find('.option-value').html();\n+                        p_label.html(label);\n+                        p_value.html(value);\n+                        parent = prev;\n+                    }\n+                    parent.next().focus();\n+                /*\n+                    setTimeout(function() {\n+                        document.execCommand('selectAll',false,null);\n+                    },100);\n+                */\n+                    parent.remove();\n+                }\n+        },\n+        //select the text when user press tab\n+        tabEvent: function (e) {\n+            setTimeout(function() {\n+                document.execCommand('selectAll',false,null);\n+            },100);\n+        },\n+        tabEventWithCopy: function(e) {\n+            if(!$('.last .option-value').html().length) {\n+                $('.last .option-value').html(this.table.find('.last .option-label').html());\n+            }\n+            this.tabEvent(e);\n+        },\n+        //get a template of a line of the table for other internal functions \n+        fieldModel : function() {\n+            return openerp.qweb.render('webiste.form.editor.wizard.option.template');\n+        },\n+        //manage events to add a line on the table\n+        addField: function(button) {\n+            var self = this;\n+            return function(e) {\n+                if((e.keyCode === 9) || button) {\n+                    e.preventDefault();\n+                    var tb_line = $(self.fieldModel());\n+                    tb_line.find('input.delete').remove();\n+                    self.offAddField();\n+                    \n+                    self.table.find('.o_form-editor-add').remove();\n+                    self.table.find('.last').removeClass('last');\n+                    tb_line.find('a.delete').on('click',function(e) {\n+                            $(this).parent().parent().remove();\n+                    });\n+                    self.table.find('tbody').append(tb_line);\n+                    \n+                    self.table.find('.last .option-label').focus();\n+                    setTimeout(function() {\n+                        document.execCommand('selectAll',false,null);\n+                    },100);\n+                    self.onAddField();\n+                }\n+            };\n+        },\n+        //add options from the wizard to the form field \n+        //target : container for options\n+        //type : the type of the form field to link templates\n+        //params: various parameters to edit custom fields on the template\n+        addOptions: function (target,type,params) {\n+            var self = this;\n+            return function() {\n+                var fullOptions = '';\n+                var j = 0;\n+                target.html(' ');\n+                self.table.find('tr').each(function(i,elem) {\n+                    var check = $(elem).find('input.delete');\n+                    var label = $(elem).find('.option-label').html();\n+                    var value = $(elem).find('.option-value').html();\n+                    \n+                    if(label && value)\n+                        if((label.length > 0) && (value.length > 0)) {\n+                            params.label = label;\n+                            params.value = value;\n+                            params.id    = params.id_label+'-'+j;\n+                            if(!check || !check.length) params.visible = '';\n+                            else if (check.is(':checked')) params.visible = '';\n+                            else params.visible = 'hidden';\n+                            j++;\n+                            fullOptions += openerp.qweb.render('website.form.editor.template.option.'+type,params);\n+                        }\n+                });\n+                \n+                target.append(fullOptions);\n+            };\n+        },\n+        //load \n+        restore: function() {\n+            var tb_line = $(this.fieldModel());\n+            if(!this.table) return;\n+            var parent = this.table.find('tbody');\n+            tb_line.find('input.delete').remove();\n+            tb_line.find('a.delete').on('click',function(e) {\n+                    $(this).parent().parent().remove();\n+            });\n+            this.table.find('.o_tb-actions input').addClass('hidden');\n+            $(this.table.find('th')[1]).removeClass('hidden');\n+            parent.html('');\n+            parent.append(tb_line);\n+            this.offAddField();\n+            this.onAddField();\n+            \n+        },\n+        loadData: function (wizard,target, get) {\n+            var self = this;\n+            var tb_line = $(self.fieldModel());\n+            var field_selected = wizard.find('.form-select-field').val();\n+            var field_properties = this.parent.$target.closest('form[action*=\"/website_form/\"]').data('fields').all[field_selected];\n+            this.lock = (   (field_selected != 'custom') &&\n+                            (field_properties.relation || field_properties.selection)   );\n+\n+            if(this.lock)   {\n+                tb_line.find('a.delete').remove();\n+                tb_line.find('.option-value').addClass('hidden');\n+                $(this.table.find('th')[1]).addClass('hidden');\n+                this.table.find('.o_tb-actions input').removeClass('hidden');\n+            }\n+            else{\n+                tb_line.find('input.delete').remove();\n+                tb_line.find('.option-value').removeClass('hidden');\n+                $(this.table.find('th')[1]).removeClass('hidden');\n+                this.table.find('.o_tb-actions input').addClass('hidden');\n+            }\n+            var tb_last = tb_line.clone();\n+            var tb_append;\n+            var last = self.table.find('.last');\n+            var parent = self.table.find('tbody');\n+            var dataList = target.children();\n+            \n+            last.remove();\n+            parent.html('');\n+            tb_line = $(tb_line[0]);\n+            \n+            tb_line.removeClass('last');\n+            \n+            if(!dataList.length) {\n+                parent.append('<td colspan=\"3\"><strong>'+_t('No Data')+'</strong></td>');\n+                return;\n+            }\n+            this.j = 3;\n+            $.each(dataList,function (i,elem) {\n+\n+                var option = get(elem);\n+                \n+                if(option.last && !self.lock) tb_append = tb_last.clone();\n+                else tb_append = tb_line.clone();\n+                tb_append.find('.option-label').attr('tabindex', self.j ++);\n+                tb_append.find('.option-value').attr('tabindex', self.j ++);\n+                tb_append.find('.option-label').html(option.label).on('focus', self.tabEvent);\n+                tb_append.find('.option-value').html(option.value).on('focus', self.tabEvent);\n+                if(!self.lock) tb_append.find('a.delete').on('click',function(e) {\n+                    $(this).parent().parent().remove();\n+                });\n+                else {\n+                    if(!$(elem).hasClass('hidden')) tb_append.find('input').prop('checked', true);\n+                    tb_append.find('.option-value').prop('contenteditable',false);\n+                }\n+                    \n+                parent.append(tb_append);\n+            \n+            });\n+            this.table.find('.o_tb-actions input')  .prop('checked',true)\n+                                                    .on('click',this.checkAll(this));\n+            this.table.find('input.delete')         .on('click',this.checkAllStates(this));\n+            this.checkAllStates(this)();\n+            wizard.find('.form-group:not(:has(table)) input:not([tabindex]):visible').each(function(i,elem) {\n+                console.log(elem);\n+                $(elem).attr('tabindex', self.j++);\n+            });\n+        }\n+        \n+    });\n+\n+    //////////////////////////\n+    //  Form Widget Editor  //\n+    //----------------------//\n+    // All functions to     //\n+    // edit snippet form    //\n+    //////////////////////////\n+\n+\n+    website.snippet.options.editForm = website.snippet.Option.extend({\n+        wizard: null,\n+        validate: function (DefferedForm) {\n+                var self = this;\n+                var model_sel = this.wizard.find('.form-select-action').val();\n+\n+                this.$target.attr('data-model', model_sel);\n+                this.$target.attr('action','/website_form/'+model_sel);\n+                this.$target.attr('data-success',this.wizard.find('#success').val());\n+                this.$target.attr('data-fail',this.wizard.find('#fail').val());\n+\n+                this.getModel(model_sel).then(function(){\n+                    var mail = self.wizard.find('.o_form-action-mailto input[type=hidden]').val();\n+\n+                    if(self.wizard.find('select').val() != 'mail.mail') {\n+                        DefferedForm.resolve();\n+                    }\n+                    else if(mail.length > 0) {\n+                        new openerp.Model(openerp.website.session,\"res.partner\")\n+                        .call(\"find_or_create\",[mail], {context: website.get_context()}).then(function(id) {\n+                            console.log(id);\n+                            if(id) {\n+                                var hidden_email = self.$target.find('.hidden_email_website_form_editor');\n+                                \n+                                if(!hidden_email || !hidden_email.length) {\n+                                    self.$target.append('<input type=\"hidden\" class=\"hidden_email_website_form_editor form-data\" name=\"recipient_ids\" value=\"'+id+'\" />');\n+                                }\n+                                else {\n+                                    hidden_email.val(id);\n+                                }\n+                                DefferedForm.resolve();\n+                            }\n+                            else {\n+                                DefferedForm.reject();\n+                            }\n+                        })\n+                        .fail(function() {DefferedForm.reject();});\n+                    }\n+\n+                    $('a[href=#snippet_form]')\n+                                        .parent()\n+                                        .addClass('active');\n+                    $('button[data-action=snippet]').trigger('click');\n+                    \n+                    $('#oe_snippets')   .removeClass('hidden')\n+                                        .find('.active')\n+                                        .removeClass('active');\n+                    $('#oe_snippets')   .find('#snippet_form')\n+                                        .addClass('active');\n+                    self.wizard.modal('hide');\n+                    //self.getModel();\n+                \n+                });\n+        },\n+        organizeForm: function() {\n+            if(this.wizard.find('select').val() == 'mail.mail') {\n+                this.wizard.find('.o_form-action-mailto').removeClass('hidden');\n+            }\n+            else {\n+                this.wizard.find('.o_form-action-mailto').addClass('hidden');\n+            }\n+        },\n+        \n+        execute: function (type, value, $li) {\n+            if (type == 'click') this.on_prompt();\n+        },\n+        \n+        loadData: function(){\n+            this.wizard.find('#formEditor-select-action').val(this.$target.attr('data-model'));\n+            this.wizard.find('#success').val(this.$target.attr('data-success'));\n+        },\n+        on_prompt: function () {\n+            var self = this;\n+            this.DefFormPopUp = $.Deferred();\n+            \n+            new openerp.Model(openerp.website.session,\"website.form\")\n+            .call(\"search_read\", [[],['model_name','model_id','name','metadata_field_id']], {context: website.get_context()})\n+\n+            .then(function(options_list) {\n+                var options = '';\n+                var res_partner = new openerp.Model(openerp.website.session,\"res.partner\");\n+                $.each(options_list, function(i,elem) {\n+                    options += '<option value=\"'+elem.model_name+'\">'+elem.name+'</option>';\n+                });\n+                self.wizard = $(openerp.qweb.render('website.form.editor.wizard.template.modelSelection',{'options': options}));\n+                self.wizard.appendTo('body').modal({\"keyboard\" :true});\n+                self.wizard.on('hidden.bs.modal', _.bind(self.removeWizard, self));\n+                self.loadData();\n+                \n+                self.wizard.find('.o_form-action-mailto input[type=hidden]').select2({\n+                    enable: true,\n+                    initSelection: function(elem, callback) {\n+                        console.log(elem,callback);\n+                        var id_partner = parseInt(self.$target.find('.hidden_email_website_form_editor').val(),10);\n+                        if(!id_partner) {\n+                            callback();\n+                            return;\n+                        }\n+                        new openerp.Model(openerp.website.session,\"res.partner\")\n+                        .call('read',[[id_partner], ['email'], website.get_context()]).then(function(email_label){\n+                            callback({id:email_label[0].email, text:email_label[0].email});\n+                        });\n+                    },\n+                    query: function(query) {\n+                        var data = {results:[{id:query.term, text:query.term}]};\n+                        res_partner.call(\"search_read\",[[['email', '=like', query.term+'%']],['email']], { limit: 5, context: website.get_context()}).then(function(tlist) {\n+                            $.each(tlist, function(i, obj) {\n+                                data.results.push({id:obj.email, text:obj.email});\n+                            });\n+                            query.callback(data);\n+                        });\n+                    }\n+                });\n+\n+                self.organizeForm();\n+                self.wizard.find('select').on('change',_.bind(self.organizeForm,self));\n+                self.wizard.find('.validate').on('click',_.bind(self.validate,self,self.DefFormPopUp));\n+            });\n+\n+            return self.DefFormPopUp;\n+\n+        },\n+        drop_and_build_snippet: function() {\n+            var self = this;\n+            this._super();\n+            this.on_prompt().fail(function () {  self.editor.on_remove(); });\n+        },\n+        start : function () {\n+            this._super();\n+            this.getModel = getModel;\n+            this.removeWizard = removeWizard;\n+        },\n+        clean_for_save: function () {},\n+    });\n+    \n+    //////////////////////////\n+    // Fields Widget Editor //\n+    //----------------------//\n+    // All functions to     //\n+    // edit snippet fields  //\n+    //////////////////////////\n+    \n+    website.snippet.options.editFormField = website.snippet.Option.extend({\n+          model: null,\n+          fields: null,\n+          old_action: null,\n+          wizard: null,\n+\n+        //-------------------------------\n+        //         Data loading\n+        //-------------------------------\n+        // Functions to load data from \n+        // $target to wizard assistant\n+        // for each kind of form fields\n+        //-------------------------------\n+        \n+        \n+        // Get list of fields from model\n+        getFields: function(types) {\n+            console.log(arguments);\n+            var options = '';\n+            var field_name = this.$target.find('.form-data').attr('name');\n+            var all_fields = this.$target.parent().find('.form-data');\n+            var sorted_all_fields = {};\n+            var keysSorted;\n+            var all_fields_name = [];\n+            var form = this.$target.closest('form');\n+\n+            all_fields.each(function(i,val) {\n+                all_fields_name[i] = $(val).attr('name');\n+            });\n+            \n+            var field = form.data('fields').all[field_name];\n+            this.lockCheckboxMultiple(field);\n+            options += (!!field) ? '<option selected=\"selected\" value=\"'+field.name+'\">'+field.label+'</option>':'';\n+\n+            $.each(types, function (j,type) {\n+                if(form.data('fields')[type]){\n+                    sorted_all_fields = _.extend(sorted_all_fields, form.data('fields')[type]);\n+                }\n+            });\n+\n+            // get a sorted list of keys to put option sorted alphabetically\n+            console.log(sorted_all_fields);\n+            keysSorted = Object.keys(sorted_all_fields).sort(function(a,b){\n+                a = sorted_all_fields[a].label.toLowerCase();\n+                b = sorted_all_fields[b].label.toLowerCase();\n+                return a == b ? 0 : (a > b ? 1:-1);\n+            });\n+            console.log(keysSorted);\n+            $.each(keysSorted, function(i,key) {\n+                if(key) {\n+                    options += '<option value=\"'+sorted_all_fields[key].name+'\">'+sorted_all_fields[key].label+'</option>';\n+                }\n+            });\n+            \n+            this.wizard.find('.form-select-field').append(options);\n+        },\n+\n+        lockCheckboxMultiple: function(field) {\n+            var multiple = this.wizard.find('.form-field-multiple');\n+            \n+            if(field === undefined) {\n+                    multiple.prop('disabled',false);\n+                    multiple.parent().parent().removeClass('hidden');\n+                    return false;\n+                }\n+                \n+            if( (field.type == 'many2many') ||\n+                (field.type == 'one2many')  ||\n+                (field.type == 'manyBinary2many') ) {\n+                 if(multiple) {\n+                     multiple.prop('checked',true);\n+                     multiple.parent().parent().addClass('hidden');\n+                     multiple.prop('disabled','disabled');\n+                 }\n+            }else {\n+                if(multiple){\n+                     multiple.prop('checked',false);\n+                     multiple.parent().parent().addClass('hidden');\n+                     multiple.prop('disabled','disabled');\n+                }\n+                if(!((field.type == 'many2one') || (field.type == 'selection'))) return false;\n+            }\n+            return true;\n+        },\n+        getValues: function (selectFields) {\n+            var target = function(data){\n+                return {     values:      data,\n+                             children:    function() {return this.values;}};\n+            };\n+            var self = this;\n+            var selected_field = selectFields.children(\":selected\").val();\n+            var form  = this.$target.closest('form');\n+            var field = form.data('fields').all[selected_field];\n+           \n+            this.lockCheckboxMultiple(field);\n+            \n+            if (!field) {\n+                this.wizard.find('.form-field-label').val('');\n+                this.optionEditor.restore();\n+                return;\n+            }\n+            \n+            if(field.relation && field.relation != 'ir.attachment') {\n+                openerp.jsonRpc('/web/dataset/call_kw', 'call', {\n+                                model:  field.relation,\n+                                method: 'search_read',\n+                                args:[[],['display_name']],\n+                                kwargs:{\"context\": website.get_context()}\n+                                \n+                    }).then(function (data) {\n+                        self.optionEditor.loadData(self.wizard,target(data), function(data) {\n+                            return {label: data.display_name, value: data.id, last: 0};\n+                        });\n+                    });\n+            }\n+            else if(field.selection) {\n+                this.optionEditor.loadData(this.wizard,target(field.selection), function(data) {\n+                    return {label: data[1], value: data[0], last: 0};\n+                });\n+            }\n+            else {\n+                this.optionEditor.restore();\n+            }\n+            this.wizard.find('.form-field-label').val(field.label);\n+            this.wizard.find('.form-field-required').prop('checked',field.required);\n+        },\n+        hiddenLoadData: function() {\n+            this.getFields(['integer', 'date','char','text','float']);\n+            this.wizard.find('.field_name').html(_t('Hidden Field'));\n+            this.wizard.find('.form-field-label').val(this.$target.find('.form-data').prop('name'));\n+            this.wizard.find('.form-field-required').parent().parent().addClass('hidden');\n+            this.wizard.find('.form-field-help').parent().parent().addClass('hidden');\n+            this.wizard.find('.form-field-value').val(this.$target.find('.form-data').val());\n+        },\n+        inputLoadData: function() {\n+            this.wizard.find('.field_name').html(_t('Text Field'));\n+            this.getFields(['integer', 'date', 'char', 'text', 'float']);\n+            this.wizard.find('.form-field-append-check') .prop('checked',(this.$target.find('.append').length > 0));\n+            this.wizard.find('.form-field-prepend-check').prop('checked',(this.$target.find('.prepend').length > 0));\n+            this.wizard.find('.form-field-append')       .val(this.$target.find('.append').html());\n+            this.wizard.find('.form-field-prepend')      .val(this.$target.find('.prepend').html());\n+        },\n+        textareaLoadData: function() {\n+            this.wizard.find('.field_name').html(_t('Textarea'));\n+            this.getFields(['char', 'text', 'html']);\n+            this.wizard.find('.form-field-placeholder')  .val(this.$target.find('.form-data').prop('placeholder'));        // Load placeholder on wizard\n+        },\n+        inputfileLoadData: function() {\n+            this.wizard.find('.field_name').html(_t('Upload Field'));\n+            this.getFields(['binary', 'manyBinary2many', 'oneBinary2many']);\n+            this.wizard.find('.form-field-placeholder')  .val(this.$target.find('.form-data').prop('placeholder'));\n+            this.wizard.find('.form-button-label')       .val(this.$target.find('.browse-label').html());\n+            this.wizard.find('.form-field-multiple')     .prop('checked',this.$target.find('input[type=file]').attr('multiple') == \"multiple\");\n+        },\n+        selectLoadData: function() {\n+            var self = this;\n+            this.wizard.find('.field_name').html(_t('Select Field'));\n+            this.getFields(['integer', 'date','char','text','float','many2one','one2many','many2many','selection']);\n+            this.wizard.find('.form-field-multiple').prop('checked',self.$target.find('.form-data').attr('multiple') == \"multiple\");\n+            this.wizard.find('.form-field-autocomplete').prop('checked',(self.$target.find('.form-data').attr('autocomplete') == 'on'));\n+            self.optionEditor.enable(    this.wizard,\n+                                        self.$target.find('.wrap-options'),\n+                                        function (elem) {\n+                                            elem = $(elem);\n+                                            return {label : elem.html(), value : elem.val(), last: !$(elem).next().length};\n+                                        });\n+        },\n+        checkboxLoadData: function() {\n+            this.wizard.find('.field_name').html(_t('Checkbox Field'));\n+            this.getFields(['one2many','many2many']);\n+            this.wizard.find('.form-field-inline').prop('checked',this.$target.find('.wrap-options label').hasClass('checkbox-inline'));\n+            \n+            this.optionEditor.enable(   this.wizard,\n+                                        this.$target.find('.wrap-options'),\n+                                        function (elem) {\n+                                            elem = $(elem);\n+                                            return {label : elem.find('.option').html(), value : elem.find('input[type=checkbox]').val(), last: !$(elem).next().length};\n+                                        });\n+        },\n+        radioLoadData: function() {\n+            this.wizard.find('.field_name').html(_t('Radio Field'));\n+            this.getFields(['integer', 'date','char','text','float','many2one','selection']);\n+            this.wizard.find('.form-field-inline').prop('checked',this.$target.find('.wrap-options label').hasClass('checkbox-inline'));\n+            \n+            this.optionEditor.enable(   this.wizard,\n+                                        this.$target.find('.wrap-options'),\n+                                        function (elem) {\n+                                            elem = $(elem);\n+                                            return {label : elem.find('.option').html(), value : elem.find('input[type=radio]').val(), last: !$(elem).next().length};\n+                                        });\n+        },\n+        defaultLoadData: function () {\n+            this.wizard.find('.form-field-label')           .val(this.$target.find('label').html());                              // Load label on this.wizard\n+            this.wizard.find('.form-field-placeholder')     .val(this.$target.find('.form-data').prop('placeholder'));            // Load placeholder on wizard\n+            this.wizard.find('.form-field-help')            .val(this.$target.find('.help-block').html());                        // Load help text on this.wizard\n+            this.wizard.find('.form-field-required')        .prop('checked',this.$target.find('.form-data').prop('required'));    // Check required option on this.wizard if enabled\n+            this.wizard.find('.form-select-field')          .val(this.$target.find('.form-data').attr('name'));                   // Load action on this.wizard\n+        },\n+        \n+        //------------------------------------\n+        //         Validate and Update form\n+        //------------------------------------\n+        // Functions to update form fields\n+        // from data on the wizard assistant\n+        //------------------------------------\n+        hiddenValidate: function() {\n+            this.$target.find('.form-data').val(this.wizard.find('.form-field-value').val());\n+            this.$target.find('.help-block').html('');\n+        },\n+        textareaValidate: function() {\n+            this.$target.find('.form-data').prop('placeholder',this.wizard.find('.form-field-placeholder').val());\n+        },\n+        inputfileValidate: function() {\n+            var multiple = this.wizard.find('.form-field-multiple').is(':checked') ? 'multiple': false;\n+            this.$target.find('.form-data').prop('placeholder',this.wizard.find('.form-field-placeholder').val());\n+            this.$target.find('.browse-label').html(this.wizard.find('.form-button-label').val());\n+            this.$target.find('input[type=file]').attr('multiple',multiple);\n+        },\n+        selectValidate: function() {\n+            var optionsSelector = this.$target.find('.wrap-options');\n+            var i = 0;\n+            var multiple = this.wizard.find('.form-field-multiple').is(':checked') ? 'multiple': false;\n+            this.$target.find('.form-data').attr('multiple',multiple);\n+            var autocomplete = this.wizard.find('.form-field-autocomplete').is(':checked')? 'on':'off';\n+            this.$target.find('.form-data').attr('autocomplete',autocomplete);\n+            this.optionEditor.addOptions(optionsSelector,'select',{id_label:''})();\n+        },\n+        checkboxValidate: function () {\n+            var optionsSelector = this.$target.find('.wrap-options');\n+            var i = 0;\n+            var field_name = this.wizard.find('.form-select-field').val();\n+            var name = (field_name  == 'custom') ? $.trim(this.wizard.find('.form-field-label').val()) : field_name;\n+            this.optionEditor.addOptions(optionsSelector,'checkbox',{id_label:name})();\n+            if(this.wizard.find('.form-field-inline').is(':checked')) {\n+                this.$target.find('.wrap-options label').addClass('checkbox-inline');\n+                this.$target.find('.wrap-options div').addClass('div-inline');\n+            }\n+            else {\n+                this.$target.find('.wrap-options label').removeClass('checkbox-inline');\n+                this.$target.find('.wrap-options div').removeClass('div-inline');\n+            }\n+        },\n+        radioValidate: function () {\n+            var optionsSelector = this.$target.find('.wrap-options');\n+            var i = 0;\n+            var field_name = this.wizard.find('.form-select-field').val();\n+            var name = (field_name  == 'custom') ? $.trim(this.wizard.find('.form-field-label').val()) : field_name;\n+            this.optionEditor.addOptions(optionsSelector,'radio',{id_label:name})();\n+            $(this.$target.find('input[type=radio]')[0]).attr('checked', 'checked');\n+            if(this.wizard.find('.form-field-inline').is(':checked')) {\n+                this.$target.find('.wrap-options label').addClass('checkbox-inline');\n+                this.$target.find('.wrap-options div').addClass('div-inline');\n+            }\n+            else {\n+                this.$target.find('.wrap-options label').removeClass('checkbox-inline');\n+                this.$target.find('.wrap-options div').removeClass('div-inline');\n+            }\n+        },\n+        inputValidate: function() {\n+\n+                var append_t      = this.wizard.find('.form-field-append').val();\n+                var prepend_t     = this.wizard.find('.form-field-prepend').val();\n+                \n+                var append_exist  = (this.$target.find('.append').length > 0) ;\n+                var prepend_exist = (this.$target.find('.prepend').length > 0) ;\n+                \n+                var append_check  = (append_t.length > 0);\n+                var prepend_check = (prepend_t.length > 0);\n+                \n+                this.$target.find('.form-data').prop('placeholder',this.wizard.find('.form-field-placeholder').val());\n+                \n+                // Remove or add Append or Prepend text to the input\n+                if(!append_exist && append_check) {\n+                    this.$target.find('.wrap-unwrap').append('<span class=\"input-group-addon append\">'+append_t+'</span>');\n+                    append_exist = true;\n+                }\n+                else if(append_exist && !append_check) {\n+                    this.$target.find('.append').remove();\n+                    append_exist = false;\n+                }\n+                \n+                if(!prepend_exist && prepend_check) {\n+                    this.$target.find('.wrap-unwrap').prepend('<span class=\"input-group-addon prepend\">'+prepend_t+'</span>');\n+                    prepend_exist = true;\n+                }\n+                else if(prepend_exist && !prepend_check) {\n+                    this.$target.find('.prepend').remove();\n+                    prepend_exist = false;\n+                }\n+            \n+                if(!append_exist && !prepend_exist) {\n+                    this.$target.find('.wrap-unwrap').removeClass('input-group');\n+                }\n+                else if(append_exist || prepend_exist) {\n+                    this.$target.find('.wrap-unwrap').addClass('input-group');\n+                }\n+            \n+        },\n+        defaultValidate: function () {\n+            var name,help;\n+            var field_name; // custom or variable name from model\n+            var required;\n+            var field_label = this.wizard.find('.form-field-label');\n+            ValidOption = true;\n+            if(!field_label.val().length) {\n+                console.log('test warning on label');\n+                field_label.parent().parent()\n+                           .addClass('has-error has-feedback').children('div')\n+                           .append('<i class=\"fa fa-close form-control-feedback\"></i>');\n+                return;\n+            }\n+\n+            field_name  = this.wizard.find('.form-select-field').val();\n+            \n+            // get name/id from label for custom or from field_name;\n+            name        = (field_name  == 'custom') ? $.trim(field_label.val()) : field_name;\n+    \n+            required    = (this.wizard.find('.form-field-required').is(':checked')) ? true:false;\n+            help        = this.wizard.find('.form-field-help').val();\n+            \n+            this.$target.find('.form-data').attr('data-field',field_name);\n+            this.$target.find('.form-data').attr('id',name);\n+            \n+            this.$target.find('.form-data').attr('name',name);\n+            this.$target.find('.form-data').attr('data-cke-saved-name',name);\n+            this.$target.find('.form-data').attr('required',required);\n+            if(required) {\n+                this.$target.find('label').removeClass('o_light');\n+            }\n+            else {\n+                this.$target.find('label').addClass('o_light');\n+            }\n+\n+            if(help.length > 0) {\n+                if(this.$target.find('.help-block').length) {\n+                    this.$target.find('.help-block').html(help);\n+                }\n+                else {\n+                    this.$target.find('.form-data').parent().append('<p class=\"help-block\">'+help+'</p>');\n+                }\n+            }\n+            else {\n+                this.$target.find('.help-block').remove();\n+            }\n+            \n+            this.$target.find('.control-label').html(field_label.val());\n+            $('#oe_snippets').removeClass('hidden');\n+            this.wizard.modal('hide');\n+        },\n+\n+        confirm: function (DefferedForm) {\n+                if(ValidOption) {\n+                    DefferedForm.resolve();\n+                }\n+                else {\n+                    DefferedForm.reject();\n+                }\n+        },\n+        \n+        execute: function (type, value, $li) {\n+            if (type == 'click') {\n+                var self = this;","path":"addons/website_form_builder/static/src/js/website.form.field.editor.js","position":830,"original_position":830,"commit_id":"ef384eb6be17a6851e639b316c6757b358c35161","original_commit_id":"ef384eb6be17a6851e639b316c6757b358c35161","user":{"login":"Gorash","id":2284563,"avatar_url":"https://avatars.githubusercontent.com/u/2284563?v=3","gravatar_id":"","url":"https://api.github.com/users/Gorash","html_url":"https://github.com/Gorash","followers_url":"https://api.github.com/users/Gorash/followers","following_url":"https://api.github.com/users/Gorash/following{/other_user}","gists_url":"https://api.github.com/users/Gorash/gists{/gist_id}","starred_url":"https://api.github.com/users/Gorash/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Gorash/subscriptions","organizations_url":"https://api.github.com/users/Gorash/orgs","repos_url":"https://api.github.com/users/Gorash/repos","events_url":"https://api.github.com/users/Gorash/events{/privacy}","received_events_url":"https://api.github.com/users/Gorash/received_events","type":"User","site_admin":false},"body":"?","created_at":"2014-12-16T13:14:04Z","updated_at":"2014-12-16T13:14:04Z","html_url":"https://github.com/odoo/odoo/pull/3038#discussion_r21896038","pull_request_url":"https://api.github.com/repos/odoo/odoo/pulls/3038","_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments/21896038"},"html":{"href":"https://github.com/odoo/odoo/pull/3038#discussion_r21896038"},"pull_request":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3038"}}},"pull_request":{"url":"https://api.github.com/repos/odoo/odoo/pulls/3038","id":22630213,"html_url":"https://github.com/odoo/odoo/pull/3038","diff_url":"https://github.com/odoo/odoo/pull/3038.diff","patch_url":"https://github.com/odoo/odoo/pull/3038.patch","issue_url":"https://api.github.com/repos/odoo/odoo/issues/3038","number":3038,"state":"open","locked":false,"title":"[IMP] Form builder + asynchronous post function beta version","user":{"login":"mdo-odoo","id":8291232,"avatar_url":"https://avatars.githubusercontent.com/u/8291232?v=3","gravatar_id":"","url":"https://api.github.com/users/mdo-odoo","html_url":"https://github.com/mdo-odoo","followers_url":"https://api.github.com/users/mdo-odoo/followers","following_url":"https://api.github.com/users/mdo-odoo/following{/other_user}","gists_url":"https://api.github.com/users/mdo-odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/mdo-odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mdo-odoo/subscriptions","organizations_url":"https://api.github.com/users/mdo-odoo/orgs","repos_url":"https://api.github.com/users/mdo-odoo/repos","events_url":"https://api.github.com/users/mdo-odoo/events{/privacy}","received_events_url":"https://api.github.com/users/mdo-odoo/received_events","type":"User","site_admin":false},"body":"","created_at":"2014-10-13T07:59:39Z","updated_at":"2014-12-16T13:14:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4dfc2daf1ae477d905a47ca873be739a839095db","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/odoo/odoo/pulls/3038/commits","review_comments_url":"https://api.github.com/repos/odoo/odoo/pulls/3038/comments","review_comment_url":"https://api.github.com/repos/odoo/odoo/pulls/comments/{number}","comments_url":"https://api.github.com/repos/odoo/odoo/issues/3038/comments","statuses_url":"https://api.github.com/repos/odoo/odoo/statuses/ef384eb6be17a6851e639b316c6757b358c35161","head":{"label":"odoo-dev:master-form-builder-beta-mdo","ref":"master-form-builder-beta-mdo","sha":"ef384eb6be17a6851e639b316c6757b358c35161","user":{"login":"odoo-dev","id":7466976,"avatar_url":"https://avatars.githubusercontent.com/u/7466976?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo-dev","html_url":"https://github.com/odoo-dev","followers_url":"https://api.github.com/users/odoo-dev/followers","following_url":"https://api.github.com/users/odoo-dev/following{/other_user}","gists_url":"https://api.github.com/users/odoo-dev/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo-dev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo-dev/subscriptions","organizations_url":"https://api.github.com/users/odoo-dev/orgs","repos_url":"https://api.github.com/users/odoo-dev/repos","events_url":"https://api.github.com/users/odoo-dev/events{/privacy}","received_events_url":"https://api.github.com/users/odoo-dev/received_events","type":"Organization","site_admin":false},"repo":{"id":19853934,"name":"odoo","full_name":"odoo-dev/odoo","owner":{"login":"odoo-dev","id":7466976,"avatar_url":"https://avatars.githubusercontent.com/u/7466976?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo-dev","html_url":"https://github.com/odoo-dev","followers_url":"https://api.github.com/users/odoo-dev/followers","following_url":"https://api.github.com/users/odoo-dev/following{/other_user}","gists_url":"https://api.github.com/users/odoo-dev/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo-dev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo-dev/subscriptions","organizations_url":"https://api.github.com/users/odoo-dev/orgs","repos_url":"https://api.github.com/users/odoo-dev/repos","events_url":"https://api.github.com/users/odoo-dev/events{/privacy}","received_events_url":"https://api.github.com/users/odoo-dev/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/odoo-dev/odoo","description":"RD Dev Repository","fork":true,"url":"https://api.github.com/repos/odoo-dev/odoo","forks_url":"https://api.github.com/repos/odoo-dev/odoo/forks","keys_url":"https://api.github.com/repos/odoo-dev/odoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/odoo-dev/odoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/odoo-dev/odoo/teams","hooks_url":"https://api.github.com/repos/odoo-dev/odoo/hooks","issue_events_url":"https://api.github.com/repos/odoo-dev/odoo/issues/events{/number}","events_url":"https://api.github.com/repos/odoo-dev/odoo/events","assignees_url":"https://api.github.com/repos/odoo-dev/odoo/assignees{/user}","branches_url":"https://api.github.com/repos/odoo-dev/odoo/branches{/branch}","tags_url":"https://api.github.com/repos/odoo-dev/odoo/tags","blobs_url":"https://api.github.com/repos/odoo-dev/odoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/odoo-dev/odoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/odoo-dev/odoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/odoo-dev/odoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/odoo-dev/odoo/statuses/{sha}","languages_url":"https://api.github.com/repos/odoo-dev/odoo/languages","stargazers_url":"https://api.github.com/repos/odoo-dev/odoo/stargazers","contributors_url":"https://api.github.com/repos/odoo-dev/odoo/contributors","subscribers_url":"https://api.github.com/repos/odoo-dev/odoo/subscribers","subscription_url":"https://api.github.com/repos/odoo-dev/odoo/subscription","commits_url":"https://api.github.com/repos/odoo-dev/odoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/odoo-dev/odoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/odoo-dev/odoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/odoo-dev/odoo/issues/comments/{number}","contents_url":"https://api.github.com/repos/odoo-dev/odoo/contents/{+path}","compare_url":"https://api.github.com/repos/odoo-dev/odoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/odoo-dev/odoo/merges","archive_url":"https://api.github.com/repos/odoo-dev/odoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/odoo-dev/odoo/downloads","issues_url":"https://api.github.com/repos/odoo-dev/odoo/issues{/number}","pulls_url":"https://api.github.com/repos/odoo-dev/odoo/pulls{/number}","milestones_url":"https://api.github.com/repos/odoo-dev/odoo/milestones{/number}","notifications_url":"https://api.github.com/repos/odoo-dev/odoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/odoo-dev/odoo/labels{/name}","releases_url":"https://api.github.com/repos/odoo-dev/odoo/releases{/id}","created_at":"2014-05-16T11:16:19Z","updated_at":"2014-12-03T12:49:58Z","pushed_at":"2014-12-16T13:11:49Z","git_url":"git://github.com/odoo-dev/odoo.git","ssh_url":"git@github.com:odoo-dev/odoo.git","clone_url":"https://github.com/odoo-dev/odoo.git","svn_url":"https://github.com/odoo-dev/odoo","homepage":"https://www.odoo.com","size":960025,"stargazers_count":36,"watchers_count":36,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":12,"forks":15,"open_issues":12,"watchers":36,"default_branch":"master"}},"base":{"label":"odoo:master","ref":"master","sha":"4720c8898b24a0eb60232697f827bed3ebcf40ab","user":{"login":"odoo","id":6368483,"avatar_url":"https://avatars.githubusercontent.com/u/6368483?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo","html_url":"https://github.com/odoo","followers_url":"https://api.github.com/users/odoo/followers","following_url":"https://api.github.com/users/odoo/following{/other_user}","gists_url":"https://api.github.com/users/odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo/subscriptions","organizations_url":"https://api.github.com/users/odoo/orgs","repos_url":"https://api.github.com/users/odoo/repos","events_url":"https://api.github.com/users/odoo/events{/privacy}","received_events_url":"https://api.github.com/users/odoo/received_events","type":"Organization","site_admin":false},"repo":{"id":19745004,"name":"odoo","full_name":"odoo/odoo","owner":{"login":"odoo","id":6368483,"avatar_url":"https://avatars.githubusercontent.com/u/6368483?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo","html_url":"https://github.com/odoo","followers_url":"https://api.github.com/users/odoo/followers","following_url":"https://api.github.com/users/odoo/following{/other_user}","gists_url":"https://api.github.com/users/odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo/subscriptions","organizations_url":"https://api.github.com/users/odoo/orgs","repos_url":"https://api.github.com/users/odoo/repos","events_url":"https://api.github.com/users/odoo/events{/privacy}","received_events_url":"https://api.github.com/users/odoo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/odoo/odoo","description":"Odoo (formerly OpenERP). Open Source Apps To Grow Your Business.","fork":false,"url":"https://api.github.com/repos/odoo/odoo","forks_url":"https://api.github.com/repos/odoo/odoo/forks","keys_url":"https://api.github.com/repos/odoo/odoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/odoo/odoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/odoo/odoo/teams","hooks_url":"https://api.github.com/repos/odoo/odoo/hooks","issue_events_url":"https://api.github.com/repos/odoo/odoo/issues/events{/number}","events_url":"https://api.github.com/repos/odoo/odoo/events","assignees_url":"https://api.github.com/repos/odoo/odoo/assignees{/user}","branches_url":"https://api.github.com/repos/odoo/odoo/branches{/branch}","tags_url":"https://api.github.com/repos/odoo/odoo/tags","blobs_url":"https://api.github.com/repos/odoo/odoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/odoo/odoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/odoo/odoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/odoo/odoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/odoo/odoo/statuses/{sha}","languages_url":"https://api.github.com/repos/odoo/odoo/languages","stargazers_url":"https://api.github.com/repos/odoo/odoo/stargazers","contributors_url":"https://api.github.com/repos/odoo/odoo/contributors","subscribers_url":"https://api.github.com/repos/odoo/odoo/subscribers","subscription_url":"https://api.github.com/repos/odoo/odoo/subscription","commits_url":"https://api.github.com/repos/odoo/odoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/odoo/odoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/odoo/odoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/odoo/odoo/issues/comments/{number}","contents_url":"https://api.github.com/repos/odoo/odoo/contents/{+path}","compare_url":"https://api.github.com/repos/odoo/odoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/odoo/odoo/merges","archive_url":"https://api.github.com/repos/odoo/odoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/odoo/odoo/downloads","issues_url":"https://api.github.com/repos/odoo/odoo/issues{/number}","pulls_url":"https://api.github.com/repos/odoo/odoo/pulls{/number}","milestones_url":"https://api.github.com/repos/odoo/odoo/milestones{/number}","notifications_url":"https://api.github.com/repos/odoo/odoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/odoo/odoo/labels{/name}","releases_url":"https://api.github.com/repos/odoo/odoo/releases{/id}","created_at":"2014-05-13T15:38:58Z","updated_at":"2014-12-16T12:21:10Z","pushed_at":"2014-12-16T12:21:10Z","git_url":"git://github.com/odoo/odoo.git","ssh_url":"git@github.com:odoo/odoo.git","clone_url":"https://github.com/odoo/odoo.git","svn_url":"https://github.com/odoo/odoo","homepage":"https://www.odoo.com","size":950709,"stargazers_count":1692,"watchers_count":1692,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1347,"mirror_url":null,"open_issues_count":1606,"forks":1347,"open_issues":1606,"watchers":1692,"default_branch":"8.0"}},"_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3038"},"html":{"href":"https://github.com/odoo/odoo/pull/3038"},"issue":{"href":"https://api.github.com/repos/odoo/odoo/issues/3038"},"comments":{"href":"https://api.github.com/repos/odoo/odoo/issues/3038/comments"},"review_comments":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3038/comments"},"review_comment":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3038/commits"},"statuses":{"href":"https://api.github.com/repos/odoo/odoo/statuses/ef384eb6be17a6851e639b316c6757b358c35161"}}}}