diff --git a/web_m2x_options/README.rst b/web_m2x_options/README.rst
index dff75f05fe73..112614317778 100644
--- a/web_m2x_options/README.rst
+++ b/web_m2x_options/README.rst
@@ -17,6 +17,12 @@ case of validation error.
If not specified, the module will avoid proposing any of the create options
if the current user has no permission rights to create the related object.
+The options provided includes as well, the possibility to propose the Most
+Recently used (MRU) values stored in the localstorage if nothing has been typed
+in the field and the uer desplays the drop-down. When the user start typing the
+field falls back to the normal behaviour.
+
+
Usage
=====
@@ -69,6 +75,10 @@ in the field's options dict
Makes many2many_tags buttons that open the linked resource
+``search_mru`` *boolean* (Default: ``False``)
+
+ Display the MRU list stored in the localstorage before the user start typing.
+
ir.config_parameter options
---------------------------
@@ -95,6 +105,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
@@ -102,7 +116,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
-------
@@ -110,13 +124,13 @@ Example
Your XML form view definition could contain::
...
-
+
...
Known issues
============
-Double check that you have no inherited view that remove ``options`` you set on a field !
+Double check that you have no inherited view that remove ``options`` you set on a field !
If nothing works, add a debugger in the first line of ``get_search_result method`` and enable debug mode in Odoo. When you write something in a many2one field, javascript debugger should pause. If not verify your installation.
Roadmap
diff --git a/web_m2x_options/static/src/js/form.js b/web_m2x_options/static/src/js/form.js
index f2a281725b4b..41d4e6155d33 100644
--- a/web_m2x_options/static/src/js/form.js
+++ b/web_m2x_options/static/src/js/form.js
@@ -5,7 +5,7 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
"use strict";
var $ = require("$");
- var core = require('web.core'),
+ var core = require('web.core'),
data = require('web.data'),
Dialog = require('web.Dialog'),
Model = require('web.Model'),
@@ -17,7 +17,8 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
'web_m2x_options.create_edit',
'web_m2x_options.limit',
'web_m2x_options.search_more',
- 'web_m2x_options.m2o_dialog',];
+ 'web_m2x_options.m2o_dialog',
+ 'web_m2x_options.search_mru',];
// In odoo 9.c FielMany2One is not exposed by form_relational
// To bypass this limitation we use the widget registry to get the
@@ -104,6 +105,27 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
}
},
+ compute_mru_key: function(){
+ var self = this,
+ model = self.view.model,
+ db = self.session.db,
+ view_id = self.view.fields_view.view_id || self.view.dataset.parent_view.fields_view.view_id;
+ return db + "/" + model + "/" + view_id + "/" + self.name;
+ },
+
+ get_mru_ids: function(){
+ var mru_option = 'web_m2x_options_mru',
+ self = this;
+ var restore_mru_ids = JSON.parse(localStorage.getItem(mru_option)),
+ key = self.compute_mru_key();
+ if (restore_mru_ids) {
+ if (!_.isUndefined(restore_mru_ids[key])){
+ return restore_mru_ids[key];
+ }
+ }
+ return [];
+ },
+
get_search_result: function (search_val) {
var Objects = new Model(this.field.relation);
var def = $.Deferred();
@@ -126,13 +148,30 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
var dataset = new data.DataSet(this, this.field.relation,
self.build_context());
+ var domain_list = [];
var blacklist = this.get_search_blacklist();
+ if(!_(blacklist).isEmpty()){
+ domain_list.push(['id', 'not in', blacklist]);
+ }
+ var can_search_mru = (self.options && self.is_option_set(self.options.search_mru)),
+ search_mru_undef = _.isUndefined(self.options.search_mru),
+ search_mru = self.is_option_set(self.view.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).isEmpty()){
+ domain_list.push(['id', 'in', mru_ids]);
+ in_search_mru = true;
+ }
+ }
this.last_query = search_val;
var search_result = this.orderer.add(dataset.name_search(
search_val,
new data.CompoundDomain(
- self.build_domain(), [["id", "not in", blacklist]]),
+ self.build_domain(), domain_list),
'ilike', this.limit + 1,
self.build_context()));
@@ -149,13 +188,25 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
// possible selections for the m2o
var values = _.map(data, function (x) {
x[1] = x[1].split("\n")[0];
- return {
+ var val= {
label: _.str.escapeHTML(x[1]),
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) {
@@ -188,7 +239,7 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
search_more_undef = _.isUndefined(self.options.search_more) && _.isUndefined(self.view.ir_options['web_m2x_options.search_more']),
search_more = self.is_option_set(self.view.ir_options['web_m2x_options.search_more']);
- if (values.length > self.limit && (can_search_more || search_more_undef || search_more)) {
+ if ((values.length > self.limit || in_search_mru) && (can_search_more || search_more_undef || search_more)) {
values = values.slice(0, self.limit);
values.push({
label: _t("Search More..."),
@@ -256,6 +307,68 @@ odoo.define('web_m2x_options.web_m2x_options', function (require) {
});
return def;
+ },
+
+ update_mru_ids: function(){
+ var self = this,
+ mru_option = 'web_m2x_options_mru';
+ var key = self.compute_mru_key();
+ // 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(self.get_value(true)) < 0 && self.get_value(true)){
+ if (queue.length < 5) {
+ // add the new element at the beginning
+ queue.unshift(self.get_value(true));
+ }else {
+ // remove the last element
+ queue.pop();
+ // add the new element at the beginning
+ queue.unshift(self.get_value(true));
+ }
+ restore_mru_ids[key] = queue;
+ }else{
+ // if the element already exist in the stack
+ if (queue.indexOf(self.get_value(true)) >= 0 && self.get_value(true)){
+ var index = queue.indexOf(self.get_value(true));
+ // remove the element from the list
+ queue.splice(index, 1);
+ // and put it back at the beginning
+ queue.unshift(self.get_value(true));
+ }
+ }
+ }else{
+ // if the element is the first one
+ if (self.get_value(true)){
+ restore_mru_ids[key] = [self.get_value(true)];
+ }
+ }
+ localStorage.setItem(mru_option, JSON.stringify(restore_mru_ids));
+ }else {
+ // first time to create an entry in the localstorage
+ if (self.get_value(true)){
+ var values = {}
+ values[key] = [self.get_value(true)]
+ localStorage.setItem(mru_option, JSON.stringify(values));
+ }
+ }
+ },
+
+ commit_value: function() {
+ var self = this;
+ // if the field value has changed and has favorites option
+ if (self._dirty_flag){
+ var can_search_mru = (self.options && self.is_option_set(self.options.search_mru)),
+ search_mru_undef = _.isUndefined(self.options.search_mru),
+ search_mru = self.is_option_set(self.view.ir_options['web_m2x_options.search_mru']);
+
+ if(can_search_mru || (search_mru_undef && search_mru)){
+ self.update_mru_ids();
+ }
+ }
}
});
diff --git a/web_m2x_options/static/src/less/web_m2x_options.less b/web_m2x_options/static/src/less/web_m2x_options.less
new file mode 100644
index 000000000000..7bd2b5338799
--- /dev/null
+++ b/web_m2x_options/static/src/less/web_m2x_options.less
@@ -0,0 +1,3 @@
+.web_m2x_dropdown_option_mru{
+ font-style: italic;
+ }
diff --git a/web_m2x_options/views/view.xml b/web_m2x_options/views/view.xml
index 9628625b5103..139b30fb5e23 100644
--- a/web_m2x_options/views/view.xml
+++ b/web_m2x_options/views/view.xml
@@ -6,6 +6,7 @@
+