summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-09-14 16:00:17 +0200
committerChristophe Simonis <chs@odoo.com>2018-09-14 16:00:17 +0200
commit9c77066f345360429a0920ca4d17af1f84a7ebea (patch)
tree469494018b2da134a8ddb5f51930566c1d39bf8e /addons/web/static
parent5c11e0d6f9dcc2161735ce3fb93430b767d54cf9 (diff)
parent6c103589c15dcf97603f3e2909871cb1fefd6484 (diff)
[MERGE] forward port branch saas-11.4 up to 6c103589c15
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/js/chrome/abstract_web_client.js6
-rw-r--r--addons/web/static/src/js/core/ajax.js2
-rw-r--r--addons/web/static/src/js/core/session.js7
-rw-r--r--addons/web/static/src/js/services/ajax_service.js25
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js6
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js3
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js6
-rw-r--r--addons/web/static/tests/core/widget_tests.js37
-rw-r--r--addons/web/static/tests/helpers/mock_server.js17
-rw-r--r--addons/web/static/tests/helpers/test_utils.js10
-rw-r--r--addons/web/static/tests/views/kanban_tests.js37
-rw-r--r--addons/web/static/tests/views/list_tests.js70
12 files changed, 83 insertions, 143 deletions
diff --git a/addons/web/static/src/js/chrome/abstract_web_client.js b/addons/web/static/src/js/chrome/abstract_web_client.js
index 7a8b3ce8b01..68f35f272da 100644
--- a/addons/web/static/src/js/chrome/abstract_web_client.js
+++ b/addons/web/static/src/js/chrome/abstract_web_client.js
@@ -187,7 +187,9 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
// If it is not handled, we should display something clearer than the common crash_manager error dialog
// since it won't show anything except "Script error."
// This link will probably explain it better: https://blog.sentry.io/2016/05/17/what-is-script-error.html
- if (message === "Script error." && !file && !line && !col && !error) {
+ if (!file && !line && !col) {
+ // Chrome and Opera set "Script error." on the `message` and hide the `error`
+ // Firefox handles the "Script error." directly. It sets the error thrown by the CORS file into `error`
if (window.onOriginError) {
window.onOriginError();
delete window.onOriginError;
@@ -195,7 +197,7 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
crash_manager.show_error({
type: _t("Odoo Client Error"),
message: _t("Unknown CORS error"),
- data: {debug: _t("An unknown CORS error occured. The error probably originates from a JavaScript file served from a different origin.")},
+ data: {debug: _t("An unknown CORS error occured. The error probably originates from a JavaScript file served from a different origin. (Opening your browser console might give you a hint on the error.)")},
});
}
} else {
diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js
index 45313b99428..f844cbdaed4 100644
--- a/addons/web/static/src/js/core/ajax.js
+++ b/addons/web/static/src/js/core/ajax.js
@@ -46,7 +46,7 @@ function genericJsonRpc (fct_name, params, settings, fct) {
});
// FIXME: jsonp?
deferred.abort = function () {
- deferred.reject('communication', $.Event(), 'abort', 'abort');
+ deferred.reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
if (xhr.abort) {
xhr.abort();
}
diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js
index fcbc5872be0..694285cccdc 100644
--- a/addons/web/static/src/js/core/session.js
+++ b/addons/web/static/src/js/core/session.js
@@ -344,9 +344,9 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
}
};
- return deferred.then(function () {
+ var promise = deferred.then(function () {
if (aborted) {
- var def = $.Deferred().reject('communication', $.Event(), 'abort', 'abort');
+ var def = $.Deferred().reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
def.abort = function () {};
return def;
}
@@ -376,6 +376,9 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
xhrDef = fct(url, "call", params, options);
return xhrDef;
});
+
+ promise.abort = deferred.abort;
+ return promise;
},
url: function (path, params) {
params = _.extend(params || {});
diff --git a/addons/web/static/src/js/services/ajax_service.js b/addons/web/static/src/js/services/ajax_service.js
index bf754792932..0cecaae9da3 100644
--- a/addons/web/static/src/js/services/ajax_service.js
+++ b/addons/web/static/src/js/services/ajax_service.js
@@ -7,17 +7,20 @@ var session = require('web.session');
var AjaxService = AbstractService.extend({
rpc: function (route, args, options, target) {
- return $.Deferred(function (def) {
- session.rpc(route, args, options).then(function () {
- if (!target.isDestroyed()) {
- def.resolve.apply(def, arguments);
- }
- }, function () {
- if (!target.isDestroyed()) {
- def.reject.apply(def, arguments);
- }
- });
- }).promise();
+ var def = $.Deferred();
+ var promise = def.promise();
+ var xhrDef = session.rpc(route, args, options);
+ promise.abort = xhrDef.abort.bind(xhrDef);
+ xhrDef.then(function () {
+ if (!target.isDestroyed()) {
+ def.resolve.apply(def, arguments);
+ }
+ }).fail(function () {
+ if (!target.isDestroyed()) {
+ def.reject.apply(def, arguments);
+ }
+ });
+ return promise;
},
});
diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js
index 9c0bcdf37fe..905ea05ac1e 100644
--- a/addons/web/static/src/js/views/kanban/kanban_model.js
+++ b/addons/web/static/src/js/views/kanban/kanban_model.js
@@ -61,15 +61,11 @@ var KanbanModel = BasicModel.extend({
if (!groupByField || groupByField.type !== 'many2one') {
return $.Deferred().reject(); // only supported when grouped on m2o
}
- // ignore action default which may be for another model
- var context = _.pick(parent.context, function (value, key) {
- return key.slice(0,8) !== 'default_';
- });
return this._rpc({
model: groupByField.relation,
method: 'name_create',
args: [name],
- context: context, // todo: combine with view context
+ context: parent.context, // todo: combine with view context
})
.then(function (result) {
var newGroup = self._makeDataPoint({
diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index b343f044bc2..15c3e24116f 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -200,6 +200,7 @@ var ListRenderer = BasicRenderer.extend({
reject = columnInvisibleFields[c.attrs.name];
}
if (!reject && c.attrs.widget === 'handle') {
+ self.hasHandle = true;
self.handleField = c.attrs.name;
}
return reject;
@@ -663,8 +664,6 @@ var ListRenderer = BasicRenderer.extend({
this._computeAggregates();
$table.toggleClass('o_list_view_grouped', this.isGrouped);
$table.toggleClass('o_list_view_ungrouped', !this.isGrouped);
- this.hasHandle = this.state.orderedBy.length === 0 ||
- this.state.orderedBy[0].name === this.handleField;
if (this.isGrouped) {
$table
.append(this._renderHeader(true))
diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js
index 491d7d0f382..5cd9a216abf 100644
--- a/addons/web/static/tests/chrome/action_manager_tests.js
+++ b/addons/web/static/tests/chrome/action_manager_tests.js
@@ -1980,7 +1980,7 @@ QUnit.module('ActionManager', {
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
- self.iframe.src = 'test: ' + self.iframe.getAttribute('src');
+ self.iframe.src = 'test ' + self.iframe.getAttribute('src');
});
}
});
@@ -2002,7 +2002,7 @@ QUnit.module('ActionManager', {
if (route === '/report/check_wkhtmltopdf') {
return $.when('broken');
}
- if (route === 'test: /report/html/some_report') {
+ if (route === 'test /report/html/some_report') {
return $.when();
}
return this._super.apply(this, arguments);
@@ -2023,7 +2023,7 @@ QUnit.module('ActionManager', {
'/web/action/load',
'/report/check_wkhtmltopdf',
'notification',
- 'test: /report/html/some_report', // report client action's iframe
+ 'test /report/html/some_report', // report client action's iframe
]);
actionManager.destroy();
diff --git a/addons/web/static/tests/core/widget_tests.js b/addons/web/static/tests/core/widget_tests.js
index 19e72cb97b6..9510079e380 100644
--- a/addons/web/static/tests/core/widget_tests.js
+++ b/addons/web/static/tests/core/widget_tests.js
@@ -1,10 +1,12 @@
odoo.define('web.widget_tests', function (require) {
"use strict";
+var AjaxService = require('web.AjaxService');
var concurrency = require('web.concurrency');
var core = require('web.core');
var QWeb = require('web.QWeb');
var Widget = require('web.Widget');
+var testUtils = require('web.test_utils');
QUnit.module('core', {}, function () {
@@ -377,16 +379,47 @@ QUnit.module('core', {}, function () {
});
QUnit.test("calling _rpc on destroyed widgets", function (assert) {
- assert.expect(1);
+ assert.expect(3);
+
+ var def;
+ var parent = new Widget();
+ testUtils.addMockEnvironment(parent, {
+ session: {
+ rpc: function () {
+ def = $.Deferred();
+ def.abort = def.reject;
+ return def;
+ },
+ },
+ services: [AjaxService],
+ });
+ var widget = new Widget(parent);
+
+ widget._rpc({route: '/a/route'}).then(function () {
+ assert.ok(true, "The ajax call should be resolve");
+ });
+ def.resolve();
+ def = null;
- var widget = new Widget();
+ widget._rpc({route: '/a/route'}).always(function () {
+ throw Error("Calling _rpc on a destroyed widget should return a " +
+ "deferred that is never resolved nor rejected");
+ });
widget.destroy();
+ def.resolve();
+ def = null;
+
widget._rpc({route: '/a/route'}).always(function () {
throw Error("Calling _rpc on a destroyed widget should return a " +
"deferred that is never resolved nor rejected");
});
+ assert.ok(!def,
+ "The trigger_up is not performed and the call returns a deferred "+
+ "never resolved nor rejected");
+
assert.ok(true,
"there should be no crash when calling _rpc on a destroyed widget");
+ parent.destroy();
});
QUnit.test('start is not called when widget is destroyed', function (assert) {
diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js
index f5ddc0982d0..83bd275d9e0 100644
--- a/addons/web/static/tests/helpers/mock_server.js
+++ b/addons/web/static/tests/helpers/mock_server.js
@@ -111,7 +111,16 @@ var MockServer = Class.extend({
args = JSON.parse(JSON.stringify(args));
}
var def = this._performRpc(route, args);
- var abort = def.abort;
+
+ var abort = def.abort || def.reject;
+ if (abort) {
+ abort = abort.bind(def);
+ } else {
+ abort = function () {
+ throw new Error("Can't abort this request");
+ };
+ }
+
def = def.then(function (result) {
var resultString = JSON.stringify(result || false);
if (debug) {
@@ -125,8 +134,10 @@ var MockServer = Class.extend({
}
return $.Deferred().reject(errorString, event || $.Event());
});
- def.abort = abort;
- return def;
+
+ var promise = def.promise();
+ promise.abort = abort;
+ return promise;
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js
index b1a0467254a..7c47bf5574a 100644
--- a/addons/web/static/tests/helpers/test_utils.js
+++ b/addons/web/static/tests/helpers/test_utils.js
@@ -497,15 +497,15 @@ function addMockEnvironment(widget, params) {
var services = {ajax: null}; // mocked ajax service already loaded
intercept(widget, 'call_service', function (ev) {
var args, result;
- if (ev.data.service === 'ajax') {
+ if (services[ev.data.service]) {
+ var service = services[ev.data.service];
+ args = (ev.data.args || []);
+ result = service[ev.data.method].apply(service, args);
+ } else if (ev.data.service === 'ajax') {
// ajax service is already mocked by the server
var route = ev.data.args[0];
args = ev.data.args[1];
result = mockServer.performRpc(route, args);
- } else if (services[ev.data.service]) {
- var service = services[ev.data.service];
- args = (ev.data.args || []);
- result = service[ev.data.method].apply(service, args);
}
ev.data.callback(result);
});
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index 399095f9427..c967b42a332 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -1490,43 +1490,6 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('m2o group record created does not use action defaults', function (assert) {
- assert.expect(1);
-
- var kanban = createView({
- View: KanbanView,
- model: 'partner',
- data: this.data,
- arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
- '<templates><t t-name="kanban-box">' +
- '<div>' +
- '<field name="foo"/>' +
- '</div>' +
- '</t></templates>' +
- '</kanban>',
- groupBy: ['product_id'],
- mockRPC: function (route, args) {
- if (args.method === 'name_create') {
- assert.notOk(_.has(args.kwargs.context, 'default_name'),
- "default_* should be removed from context");
- }
- return this._super.apply(this, arguments);
- },
- viewOptions: {
- context: {
- default_name: 'default name partner',
- },
- },
- });
- kanban.renderButtons();
-
- kanban.$('.o_column_quick_create input').val('new product');
- kanban.$('.o_column_quick_create button.o_kanban_add').click();
-
- kanban.destroy();
- });
-
-
QUnit.test('quick create record fail in grouped', function (assert) {
assert.expect(8);
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index cafd529b47c..567e722c135 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -3312,76 +3312,6 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list, handle widget locks and unlocks on sort', function (assert) {
- assert.expect(6);
-
- // we need another sortable field to lock/unlock the handle
- this.data.foo.fields.amount.sortable = true;
- // resequence makes sense on a sequence field, not on arbitrary fields
- this.data.foo.records[0].int_field = 0;
- this.data.foo.records[1].int_field = 1;
- this.data.foo.records[2].int_field = 2;
- this.data.foo.records[3].int_field = 3;
-
- var list = createView({
- View: ListView,
- model: 'foo',
- data: this.data,
- arch: '<tree editable="top" default_order="int_field">' +
- '<field name="int_field" widget="handle"/>' +
- '<field name="amount" widget="float"/>' +
- '</tree>',
- });
-
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '1200.00500.00300.000.00',
- "default should be sorted by int_field");
-
- // Drag and drop the fourth line in second position
- testUtils.dragAndDrop(
- list.$('.ui-sortable-handle').eq(3),
- list.$('tbody tr').first(),
- {position: 'bottom'}
- );
-
- // Handle should be unlocked at this point
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '1200.000.00500.00300.00',
- "drag and drop should have succeeded, as the handle is unlocked");
-
- // Sorting by a field different for int_field should lock the handle
- list.$('.o_column_sortable').eq(1).click();
-
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '0.00300.00500.001200.00',
- "should have been sorted by amount");
-
- // Drag and drop the fourth line in second position (not)
- testUtils.dragAndDrop(
- list.$('.ui-sortable-handle').eq(3),
- list.$('tbody tr').first(),
- {position: 'bottom'}
- );
-
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '0.00300.00500.001200.00',
- "drag and drop should have failed as the handle is locked");
-
- // Sorting by int_field should unlock the handle
- list.$('.o_column_sortable').eq(0).click();
-
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '1200.000.00500.00300.00',
- "records should be ordered as per the previous resequence");
-
- // Drag and drop the fourth line in second position
- testUtils.dragAndDrop(
- list.$('.ui-sortable-handle').eq(3),
- list.$('tbody tr').first(),
- {position: 'bottom'}
- );
-
- assert.strictEqual(list.$('tbody span[name="amount"]').text(), '1200.00300.000.00500.00',
- "drag and drop should have worked as the handle is unlocked");
-
- list.destroy();
- });
-
QUnit.test('editable list with handle widget with slow network', function (assert) {
assert.expect(15);