From 11ce6d64004839d5f745ec1714c242105b29f4a2 Mon Sep 17 00:00:00 2001 From: Jeroen Evens Date: Wed, 2 Oct 2019 15:02:18 +0200 Subject: [PATCH] [MIG] web_m2x_options: Migration to 13.0 --- web_m2x_options/__manifest__.py | 26 ++ web_m2x_options/readme/CONTRIBUTORS.rst | 11 + web_m2x_options/static/src/js/form.js | 389 ++++++++++++++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 web_m2x_options/__manifest__.py create mode 100644 web_m2x_options/readme/CONTRIBUTORS.rst create mode 100644 web_m2x_options/static/src/js/form.js diff --git a/web_m2x_options/__manifest__.py b/web_m2x_options/__manifest__.py new file mode 100644 index 000000000..4cc4bad54 --- /dev/null +++ b/web_m2x_options/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2015 0k.io +# Copyright 2016 ACSONE SA/NV +# Copyright 2017 Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": 'web_m2x_options', + "version": "13.0.1.0.0", + 'category': 'Web', + "author": "ACSONE SA/NV, " + "0k.io, " + "Tecnativa, " + "Odoo Community Association (OCA)", + 'website': 'https://github.com/OCA/web', + 'license': 'AGPL-3', + "depends": [ + 'web', + ], + 'data': [ + 'views/view.xml' + ], + 'qweb': [ + 'static/src/xml/base.xml', + ], + 'installable': True, +} diff --git a/web_m2x_options/readme/CONTRIBUTORS.rst b/web_m2x_options/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..55e7725a3 --- /dev/null +++ b/web_m2x_options/readme/CONTRIBUTORS.rst @@ -0,0 +1,11 @@ +* David Coninckx +* Emanuel Cino +* Holger Brunn +* Nicolas JEUDY +* Yannick Vaucher +* Zakaria Makrelouf +* Tecnativa +* Jairo Llopis +* David Vidal +* Ernesto Tejeda +* Jeroen Evens diff --git a/web_m2x_options/static/src/js/form.js b/web_m2x_options/static/src/js/form.js new file mode 100644 index 000000000..63a0603c4 --- /dev/null +++ b/web_m2x_options/static/src/js/form.js @@ -0,0 +1,389 @@ +/* Copyright 2016 0k.io,ACSONE SA/NV + * * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + +odoo.define('web_m2x_options.web_m2x_options', function (require) { + "use strict"; + + var core = require('web.core'), + data = require('web.data'), + Dialog = require('web.Dialog'), + view_dialogs = require('web.view_dialogs'), + relational_fields = require('web.relational_fields'), + rpc = require('web.rpc'); + + var _t = core._t, + FieldMany2ManyTags = relational_fields.FieldMany2ManyTags, + FieldMany2One = relational_fields.FieldMany2One, + FormFieldMany2ManyTags = relational_fields.FormFieldMany2ManyTags; + + var web_m2x_options = rpc.query({ + model: "ir.config_parameter", + method: 'get_web_m2x_options', + }); + + var M2ODialog = Dialog.extend({ + template: "M2ODialog", + init: function (parent, name, value) { + this.name = name; + this.value = value; + this._super(parent, { + title: _.str.sprintf(_t("Create a %s"), this.name), + size: 'medium', + buttons: [{ + text: _t('Create'), + classes: 'btn-primary', + click: function () { + if (this.$("input").val() !== '') { + this.trigger_up('quick_create', {value: this.$('input').val()}); + this.close(true); + } else { + this.$("input").focus(); + } + }, + }, { + text: _t('Create and edit'), + classes: 'btn-primary', + close: true, + click: function () { + this.trigger_up('search_create_popup', { + view_type: 'form', + value: this.$('input').val(), + }); + }, + }, { + text: _t('Cancel'), + close: true, + }], + }); + }, + start: function () { + this.$("p").text(_.str.sprintf(_t("You are creating a new %s, are you sure it does not exist yet?"), this.name)); + this.$("input").val(this.value); + }, + /** + * @override + * @param {boolean} isSet + */ + close: function (isSet) { + this.isSet = isSet; + this._super.apply(this, arguments); + }, + /** + * @override + */ + destroy: function () { + if (!this.isSet) { + this.trigger_up('closed_unset'); + } + this._super.apply(this, arguments); + }, + }); + + FieldMany2One.include({ + + start: function () { + this._super.apply(this, arguments); + return this.get_options(); + }, + + get_options: function () { + var self = this; + if (_.isUndefined(this.ir_options_loaded)) { + this.ir_options_loaded = $.Deferred(); + this.ir_options = {}; + web_m2x_options.then(function (records) { + _(records).each(function(record) { + self.ir_options[record.key] = record.value; + }); + self.ir_options_loaded.resolve(); + }); + } + return $.when(); + }, + + is_option_set: function (option) { + if (_.isUndefined(option)) + return false; + if (typeof option === 'string') + return option === 'true' || option === 'True'; + if (typeof option === 'boolean') + return option; + return false + }, + + _onInputFocusout: function () { + var m2o_dialog_opt = this.is_option_set(this.nodeOptions.m2o_dialog) || _.isUndefined(this.nodeOptions.m2o_dialog) && this.is_option_set(this.ir_options['web_m2x_options.m2o_dialog']) || _.isUndefined(this.nodeOptions.m2o_dialog) && _.isUndefined(this.ir_options['web_m2x_options.m2o_dialog']); + if (this.can_create && this.floating && m2o_dialog_opt) { + new M2ODialog(this, this.string, this.$input.val()).open(); + } + }, + + _search: function (search_val) { + var self = this; + var def = new Promise(function (resolve) { + // add options limit used to change number of selections record + // returned. + if (!_.isUndefined(self.ir_options['web_m2x_options.limit'])) { + self.limit = parseInt(self.ir_options['web_m2x_options.limit'], 10); + } + + if (typeof self.nodeOptions.limit === 'number') { + self.limit = self.nodeOptions.limit; + } + + // add options field_color and colors to color item(s) depending on field_color value + self.field_color = self.nodeOptions.field_color; + self.colors = self.nodeOptions.colors; + + var context = self.record.getContext(self.recordParams); + var domain = self.record.getDomain(self.recordParams); + + var blacklisted_ids = self._getSearchBlacklist(); + if (blacklisted_ids.length > 0) { + domain.push(['id', 'not in', blacklisted_ids]); + } + + self._rpc({ + model: self.field.relation, + method: "name_search", + kwargs: { + name: search_val, + args: domain, + operator: "ilike", + limit: self.limit + 1, + context: context, + } + }).then(function (result) { + // possible selections for the m2o + var values = _.map(result, function (x) { + x[1] = self._getDisplayName(x[1]); + return { + label: _.str.escapeHTML(x[1].trim()) || data.noDisplayContent, + value: x[1], + name: x[1], + id: x[0], + }; + }); + + // Search result value colors + if (self.colors && self.field_color) { + var value_ids = []; + for (var index in values) { + value_ids.push(values[index].id); + } + self._rpc({ + model: self.field.relation, + method: 'search_read', + fields: [self.field_color], + domain: [['id', 'in', value_ids]] + }).then(function (objects) { + for (var index in objects) { + for (var index_value in values) { + if (values[index_value].id == objects[index].id) { + // Find value in values by comparing ids + var value = values[index_value]; + // Find color with field value as key + var color = self.colors[objects[index][self.field_color]] || 'black'; + value.label = '' + value.label + ''; + break; + } + } + } + resolve(values); + }) + + } + + // search more... if more results that max + var can_search_more = (self.nodeOptions && self.is_option_set(self.nodeOptions.search_more)), + search_more_undef = _.isUndefined(self.nodeOptions.search_more) && _.isUndefined(self.ir_options['web_m2x_options.search_more']), + search_more = self.is_option_set(self.ir_options['web_m2x_options.search_more']); + + if (values.length > self.limit) { + values = values.slice(0, self.limit); + if (can_search_more || search_more_undef || search_more) { + values.push({ + label: _t("Search More..."), + action: function () { + var prom; + if (search_val !== '') { + prom = self._rpc({ + model: self.field.relation, + method: 'name_search', + kwargs: { + name: search_val, + args: domain, + operator: "ilike", + limit: self.SEARCH_MORE_LIMIT, + context: context, + }, + }); + } + Promise.resolve(prom).then(function (results) { + var dynamicFilters; + if (results) { + var ids = _.map(results, function (x) { + return x[0]; + }); + dynamicFilters = [{ + description: _.str.sprintf(_t('Quick search: %s'), search_val), + domain: [['id', 'in', ids]], + }]; + } + self._searchCreatePopup("search", false, {}, dynamicFilters); + }); + }, + classname: 'o_m2o_dropdown_option', + }); + } + } + + var create_enabled = self.can_create && !self.nodeOptions.no_create; + // quick create + var raw_result = _.map(result, function (x) { return x[1]; }); + var quick_create = self.is_option_set(self.nodeOptions.create), + quick_create_undef = _.isUndefined(self.nodeOptions.create), + m2x_create_undef = _.isUndefined(self.ir_options['web_m2x_options.create']), + m2x_create = self.is_option_set(self.ir_options['web_m2x_options.create']); + var show_create = (!self.nodeOptions && (m2x_create_undef || m2x_create)) || (self.nodeOptions && (quick_create || (quick_create_undef && (m2x_create_undef || m2x_create)))); + if (create_enabled && !self.nodeOptions.no_quick_create && + search_val.length > 0 && !_.contains(raw_result, search_val) && + show_create) { + values.push({ + label: _.str.sprintf(_t('Create "%s"'), + $('').text(search_val).html()), + action: self._quickCreate.bind(self, search_val), + classname: 'o_m2o_dropdown_option' + }); + } + // create and edit ... + + var create_edit = self.is_option_set(self.nodeOptions.create) || self.is_option_set(self.nodeOptions.create_edit), + create_edit_undef = _.isUndefined(self.nodeOptions.create) && _.isUndefined(self.nodeOptions.create_edit), + m2x_create_edit_undef = _.isUndefined(self.ir_options['web_m2x_options.create_edit']), + m2x_create_edit = self.is_option_set(self.ir_options['web_m2x_options.create_edit']); + var show_create_edit = (!self.nodeOptions && (m2x_create_edit_undef || m2x_create_edit)) || (self.nodeOptions && (create_edit || (create_edit_undef && (m2x_create_edit_undef || m2x_create_edit)))); + if (create_enabled && !self.nodeOptions.no_create_edit && show_create_edit) { + var createAndEditAction = function () { + // Clear the value in case the user clicks on discard + self.$('input').val(''); + return self._searchCreatePopup("form", false, self._createContext(search_val)); + }; + values.push({ + label: _t("Create and Edit..."), + action: createAndEditAction, + classname: 'o_m2o_dropdown_option', + }); + } else if (values.length === 0) { + values.push({ + label: _t("No results to show..."), + }); + } + // Check if colors specified to wait for RPC + if (!(self.field_color && self.colors)) { + resolve(values); + } + }); + + }); + this.orderer.add(def); + return def; + } + }); + + FieldMany2ManyTags.include({ + events: _.extend({}, FieldMany2ManyTags.prototype.events, { + 'click .badge': '_onOpenBadge', + }), + + _onDeleteTag: function (event) { + var result = this._super.apply(this, arguments); + event.stopPropagation(); + return result; + }, + + is_option_set: function (option) { + if (_.isUndefined(option)) + return false; + if (typeof option === 'string') + return option === 'true' || option === 'True'; + if (typeof option === 'boolean') + return option; + return false + }, + + _onOpenBadge: function (event) { + var self = this; + var open = (self.nodeOptions && self.is_option_set(self.nodeOptions.open)); + if (open) { + var context = self.record.getContext(self.recordParams); + var id = parseInt($(event.currentTarget).data('id'), 10); + + if (self.mode === 'readonly') { + event.preventDefault(); + event.stopPropagation(); + self._rpc({ + model: self.field.relation, + method: 'get_formview_action', + args: [[id]], + context: context, + }) + .then(function (action) { + self.trigger_up('do_action', {action: action}); + }); + } + else { + $.when( + self._rpc({ + model: self.field.relation, + method: 'get_formview_id', + args: [[id]], + context: context, + }), + self._rpc({ + model: self.field.relation, + method: 'check_access_rights', + kwargs: {operation: 'write', raise_exception: false} + }) + ).then(function (view_id, write_access) { + var can_write = 'can_write' in self.attrs ? JSON.parse(self.attrs.can_write) : true; + new view_dialogs.FormViewDialog(self, { + res_model: self.field.relation, + res_id: id, + context: context, + title: _t("Open: ") + self.string, + view_id: view_id, + readonly: !can_write || !write_access, + on_saved: function (record, changed) { + if (changed) { + self._setValue(self.value.data, {forceChange: true}); + self.trigger_up('reload', {db_id: self.value.id}); + } + }, + }).open(); + }) + } + } + }, + }); + + FormFieldMany2ManyTags.include({ + events: _.extend({}, FormFieldMany2ManyTags.prototype.events, { + 'click .badge': '_onOpenBadge', + }), + + _onOpenBadge: function (event) { + var open = this.is_option_set(this.nodeOptions.open); + var no_color_picker = this.is_option_set( + this.nodeOptions.no_color_picker + ); + this._super.apply(this, arguments); + if (!open && !no_color_picker) { + this._onOpenColorPicker(event); + } else { + event.preventDefault(); + event.stopPropagation(); + } + }, + }); +});