diff --git a/web_m2x_options/models/ir_config_parameter.py b/web_m2x_options/models/ir_config_parameter.py index 8e7228f086e8..13b7b9d35afe 100644 --- a/web_m2x_options/models/ir_config_parameter.py +++ b/web_m2x_options/models/ir_config_parameter.py @@ -12,5 +12,6 @@ def get_web_m2x_options(self): "web_m2x_options.limit", "web_m2x_options.search_more", "web_m2x_options.m2o_dialog", + "web_m2x_options.search_mru", ] return self.sudo().search_read([["key", "in", opts]], ["key", "value"]) diff --git a/web_m2x_options/readme/USAGE.rst b/web_m2x_options/readme/USAGE.rst index 1da37a22898a..c9679c4919e4 100644 --- a/web_m2x_options/readme/USAGE.rst +++ b/web_m2x_options/readme/USAGE.rst @@ -43,6 +43,10 @@ in the field's options dict Deactivates the color picker on many2many_tags buttons to do nothing (ignored if open is set) +``search_mru`` *boolean* (Default: ``False``) + + Display the MRU list stored in the localstorage before the user start typing. + ir.config_parameter options ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -69,6 +73,10 @@ If you disable one option, you can enable it for particular field by setting "cr Whether the field should always show "Search more..." entry or not. +``web_m2x_options.search_mru`` *boolean* (Default: default value is ``False``) + + Display the MRU list stored in the localstorage before the user start typing. + To add these parameters go to Configuration -> Technical -> Parameters -> System Parameters and add new parameters like: - web_m2x_options.create: False @@ -76,6 +84,7 @@ To add these parameters go to Configuration -> Technical -> Parameters -> System - web_m2x_options.m2o_dialog: False - web_m2x_options.limit: 10 - web_m2x_options.search_more: True +- web_m2x_options.search_mru: False Example diff --git a/web_m2x_options/static/src/js/form.js b/web_m2x_options/static/src/js/form.js index 2466de52dc52..de598425c0f7 100644 --- a/web_m2x_options/static/src/js/form.js +++ b/web_m2x_options/static/src/js/form.js @@ -135,6 +135,22 @@ odoo.define("web_m2x_options.web_m2x_options", function(require) { } }, + compute_mru_key: function() { + return odoo.session_info.db + "/" + this.model + "/" + this.name; + }, + + get_mru_ids: function() { + const mru_option = "web_m2x_options_mru", + restore_mru_ids = JSON.parse(localStorage.getItem(mru_option)), + key = this.compute_mru_key(); + if (restore_mru_ids) { + if (!_.isUndefined(restore_mru_ids[key])) { + return restore_mru_ids[key]; + } + } + return []; + }, + _search: function(search_val) { var self = this; if (search_val === undefined) { @@ -163,6 +179,27 @@ odoo.define("web_m2x_options.web_m2x_options", function(require) { domain.push(["id", "not in", blacklisted_ids]); } + var can_search_mru = + self.nodeOptions && + self.is_option_set(self.nodeOptions.search_mru), + search_mru_undef = _.isUndefined(self.nodeOptions.search_mru), + search_mru = self.is_option_set( + self.ir_options["web_m2x_options.search_mru"] + ); + + var mru_ids = []; + var in_search_mru = false; + if ( + search_val == "" && + (can_search_mru || (search_mru_undef && search_mru)) + ) { + mru_ids = self.get_mru_ids(); + if (mru_ids.length > 0) { + domain.push(["id", "in", mru_ids]); + in_search_mru = true; + } + } + self._rpc({ model: self.field.relation, method: "name_search", @@ -177,14 +214,26 @@ odoo.define("web_m2x_options.web_m2x_options", function(require) { // Possible selections for the m2o var values = _.map(result, x => { x[1] = self._getDisplayName(x[1]); - return { + const val = { label: _.str.escapeHTML(x[1].trim()) || data.noDisplayContent, value: x[1], name: x[1], id: x[0], }; + if (in_search_mru) { + val.classname = "web_m2x_dropdown_option_mru"; + } + return val; }); + // If we are in a mru search, reorder the result list in the + // same order as the one stored to keep the saved preference + // order (The most recent ones first) + if (in_search_mru) { + values = _(values).sortBy(function(item) { + return mru_ids.indexOf(item.id); + }); + } // Search result value colors if (self.colors && self.field_color) { @@ -235,7 +284,7 @@ odoo.define("web_m2x_options.web_m2x_options", function(require) { self.ir_options["web_m2x_options.search_more"] ); - if (values.length > self.limit) { + if (values.length > self.limit || in_search_mru) { values = values.slice(0, self.limit); if (can_search_more || search_more_undef || search_more) { values.push({ @@ -379,6 +428,68 @@ odoo.define("web_m2x_options.web_m2x_options", function(require) { this.orderer.add(def); return def; }, + + update_mru_ids: function() { + var mru_option = "web_m2x_options_mru"; + var key = this.compute_mru_key(); + const field_val = _.isUndefined(this.value.data) ? false : this.value.data.id; + // Check if the localstorage has some items for the current model + if (localStorage.getItem(mru_option)) { + var restore_mru_ids = JSON.parse(localStorage.getItem(mru_option)); + if (restore_mru_ids[key]) { + var queue = restore_mru_ids[key]; + // If the element doesn't exist in the stack + if (queue.indexOf(field_val) < 0 && field_val) { + if (queue.length < 5) { + // Add the new element at the beginning + queue.unshift(field_val); + } else { + // Remove the last element + queue.pop(); + // Add the new element at the beginning + queue.unshift(field_val); + } + restore_mru_ids[key] = queue; + } else if (queue.indexOf(field_val) >= 0 && field_val) { + // If the element already exist in the stack + var index = queue.indexOf(field_val); + // Remove the element from the list + queue.splice(index, 1); + // And put it back at the beginning + queue.unshift(field_val); + } + } else if (field_val && key) { + // If the element is the first one and the key is well computed + restore_mru_ids[key] = [field_val]; + } + localStorage.setItem(mru_option, JSON.stringify(restore_mru_ids)); + } else if (field_val && key) { + // First time to create an entry in the localstorage if the key is well computed + const values = {}; + values[key] = [field_val]; + localStorage.setItem(mru_option, JSON.stringify(values)); + } + }, + + commitChanges: function() { + // If the field value has changed and has favorites option + const has_changed = + !_.isUndefined(this.lastChangeEvent) && + this.lastChangeEvent.name === "field_changed"; + if (this.isDirty || has_changed) { + const can_search_mru = + this.nodeOptions && + this.is_option_set(this.nodeOptions.search_mru), + search_mru_undef = _.isUndefined(this.nodeOptions.search_mru), + search_mru = this.is_option_set( + this.ir_options["web_m2x_options.search_mru"] + ); + + if (can_search_mru || (search_mru_undef && search_mru)) { + this.update_mru_ids(); + } + } + }, }); FieldMany2ManyTags.include({ diff --git a/web_m2x_options/static/src/scss/web_m2x_options.scss b/web_m2x_options/static/src/scss/web_m2x_options.scss new file mode 100644 index 000000000000..e4d8a8940fd6 --- /dev/null +++ b/web_m2x_options/static/src/scss/web_m2x_options.scss @@ -0,0 +1,3 @@ +.web_m2x_dropdown_option_mru { + font-style: italic; +} diff --git a/web_m2x_options/static/src/xml/base.xml b/web_m2x_options/static/src/xml/base.xml index a4f5ae3c7dfd..4ea0c502b5b4 100644 --- a/web_m2x_options/static/src/xml/base.xml +++ b/web_m2x_options/static/src/xml/base.xml @@ -9,4 +9,11 @@ + + + + el[0] + + +