diff --git a/addons/web/static/src/js/chrome/search_menus.js b/addons/web/static/src/js/chrome/search_menus.js
index d41052c882e..99e8bd6e799 100644
--- a/addons/web/static/src/js/chrome/search_menus.js
+++ b/addons/web/static/src/js/chrome/search_menus.js
@@ -100,9 +100,17 @@ return Widget.extend({
var controllerContext;
this.trigger_up('get_controller_context', {
callback: function (ctx) {
- controllerContext = ctx;
+ if (ctx && ctx.orderedBy) {
+ var sort = _.map(ctx.orderedBy, function (obj) {
+ var order = obj.asc ? 'ASC' : 'DESC';
+ return obj.name + ' ' + order;
+ });
+ self.searchview.dataset.set_sort(sort);
+ }
+ controllerContext = _.omit(ctx, ['orderedBy']);
},
});
+
var results = pyeval.eval_domains_and_contexts({
domains: search.domains,
contexts: [user_context].concat(search.contexts.concat(controllerContext || [])),
@@ -182,7 +190,18 @@ return Widget.extend({
category: _t("Custom Filter"),
icon: 'fa-star',
field: {
- get_context: function () { return filter.context; },
+ get_context: function () {
+ var sortParsed = JSON.parse(filter.sort || "[]");
+ var orderedBy = [];
+ _.each(sortParsed, function (sort) {
+ orderedBy.push({
+ name: sort[0] === '-' ? sort.slice(1) : sort,
+ asc: sort[0] === '-' ? false : true,
+ });
+ });
+
+ return _.defaults({}, filter.context, {orderedBy : orderedBy});
+ },
get_groupby: function () { return [filter.context]; },
get_domain: function () { return filter.domain; }
},
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index b9832996de5..0372f7cd5e7 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -3332,7 +3332,7 @@ var BasicModel = AbstractModel.extend({
model: params.modelName,
offset: params.offset || (type === 'record' ? _.indexOf(res_ids, res_id) : 0),
openGroupByDefault: params.openGroupByDefault,
- orderedBy: params.orderedBy || [],
+ orderedBy: params.orderedBy || (params.context && params.context.orderedBy) || [],
orderedResIDs: params.orderedResIDs,
parentID: params.parentID,
rawContext: params.rawContext,
@@ -4016,6 +4016,7 @@ var BasicModel = AbstractModel.extend({
if (options.context !== undefined) {
element.context = options.context;
+ element.orderedBy = options.context.orderedBy || element.orderedBy;
}
if (options.domain !== undefined) {
element.domain = options.domain;
diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js
index 02ee76bf919..df23fffa54c 100644
--- a/addons/web/static/src/js/views/list/list_controller.js
+++ b/addons/web/static/src/js/views/list/list_controller.js
@@ -78,6 +78,14 @@ var ListController = BasicController.extend({
return $.Deferred().resolve();
}
},
+ /*
+ * @override
+ */
+ getContext: function () {
+ var context = this._super.apply(this, arguments);
+ context.orderedBy = this.model.get(this.handle, {raw: true}).orderedBy || [];
+ return context;
+ },
/**
* Returns the list of currently selected res_ids (with the check boxes on
* the left)
@@ -179,6 +187,7 @@ var ListController = BasicController.extend({
} else {
this.selectedRecords = [];
}
+
params.selectedRecords = this.selectedRecords;
return this._super.apply(this, arguments);
},
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index bd4c8f8e339..fb99828d2fe 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -307,6 +307,99 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('ordered list, sort attribute in context', function (assert) {
+ assert.expect(1);
+ // Equivalent to saving a custom filter
+
+ this.data.foo.fields.foo.sortable = true;
+ this.data.foo.fields.date.sortable = true;
+
+ var list = createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '' +
+ '' +
+ '' +
+ '',
+ });
+
+ // Descending order on Foo
+ list.$('th.o_column_sortable:contains("Foo")').click();
+ list.$('th.o_column_sortable:contains("Foo")').click();
+
+ // Ascending order on Date
+ list.$('th.o_column_sortable:contains("Date")').click();
+
+ var listContext = list.getContext();
+ assert.deepEqual(listContext,
+ {
+ orderedBy: [{
+ name: 'date',
+ asc: true,
+ }, {
+ name: 'foo',
+ asc: false,
+ }]
+ }, 'the list should have the right orderedBy in context');
+ list.destroy();
+ });
+
+ QUnit.test('Loading a filter with a sort attribute', function (assert) {
+ assert.expect(2);
+
+ this.data.foo.fields.foo.sortable = true;
+ this.data.foo.fields.date.sortable = true;
+
+ var searchReads = 0;
+ var list = createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '' +
+ '' +
+ '' +
+ '',
+ context: {
+ orderedBy: [{
+ name: 'date',
+ asc: true,
+ }, {
+ name: 'foo',
+ asc: false,
+ }]
+ },
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/search_read') {
+ if (searchReads === 0) {
+ assert.strictEqual(args.sort, 'date ASC, foo DESC',
+ 'The sort attribute of the filter should be used by the initial search_read');
+ } else if (searchReads === 1) {
+ assert.strictEqual(args.sort, 'date DESC, foo ASC',
+ 'The sort attribute of the filter should be used by the next search_read');
+ }
+ searchReads += 1;
+ }
+ return this._super.apply(this,arguments);
+ },
+ });
+
+ // Simulate loading a filter
+ list.update({
+ context: {
+ orderedBy: [{
+ name: 'date',
+ asc: false,
+ }, {
+ name: 'foo',
+ asc: true,
+ }]
+ }
+ });
+
+ list.destroy()
+ });
+
QUnit.test('many2one field rendering', function (assert) {
assert.expect(1);