summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/lib/qweb/qweb-test-extend.xml8
-rw-r--r--addons/web/static/lib/qweb/qweb2.js2
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js16
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js2
-rw-r--r--addons/web/static/src/js/views/control_panel/search/search_bar.js1
-rw-r--r--addons/web/static/src/js/widgets/auto_complete.js12
-rw-r--r--addons/web/static/src/scss/form_view.scss4
-rw-r--r--addons/web/static/src/scss/layout_background.scss3
-rw-r--r--addons/web/static/src/scss/list_view.scss1
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js36
-rw-r--r--addons/web/static/tests/views/calendar_tests.js1
-rw-r--r--addons/web/static/tests/views/form_tests.js39
12 files changed, 113 insertions, 12 deletions
diff --git a/addons/web/static/lib/qweb/qweb-test-extend.xml b/addons/web/static/lib/qweb/qweb-test-extend.xml
index 007caefe383..dfd0ec46940 100644
--- a/addons/web/static/lib/qweb/qweb-test-extend.xml
+++ b/addons/web/static/lib/qweb/qweb-test-extend.xml
@@ -18,13 +18,19 @@
<t t-jquery="ul">this.attr('class', 'main');</t>
</t>
<t t-extend="jquery-extend">
+ <t t-jquery="ul" t-operation="attributes"><attribute name="title" value="Main Title" /></t>
+ </t>
+ <t t-extend="jquery-extend">
+ <t t-jquery="ul" t-operation="attributes"><attribute name="name">main-ul</attribute></t>
+ </t>
+ <t t-extend="jquery-extend">
<t t-jquery="hr:eq(1)" t-operation="replace"><footer></footer></t>
</t>
<t t-extend="jquery-extend">
<t t-jquery="footer" t-operation="inner"><b>[[end]]</b></t>
</t>
<result id="jquery-extend"><![CDATA[
- <hr/><ul class="main"><li>1</li><li>2</li><li>3</li></ul><footer><b>[[end]]</b></footer>
+ <hr/><ul class="main" title="Main Title" name="main-ul"><li>1</li><li>2</li><li>3</li></ul><footer><b>[[end]]</b></footer>
]]></result>
<t t-name="jquery-extend-clone" t-extend="jquery-extend">
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js
index d0297ee12e5..72e65f985a8 100644
--- a/addons/web/static/lib/qweb/qweb2.js
+++ b/addons/web/static/lib/qweb/qweb2.js
@@ -513,7 +513,7 @@ QWeb2.Engine = (function() {
if (operation === 'attributes') {
jQuery('attribute', child).each(function () {
var attrib = jQuery(this);
- target.attr(attrib.attr('name'), attrib.text());
+ target.attr(attrib.attr('name'), attrib.text() || attrib.attr('value'));
});
} else {
target[operation](child.cloneNode(true).childNodes);
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js
index f26a9cbe737..07646c83273 100644
--- a/addons/web/static/src/js/views/basic/basic_controller.js
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -188,12 +188,18 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
// mutex-protected as commitChanges function of x2m has to be aware of
// all final changes made to a row.
var self = this;
- this.savingDef = this.mutex.getUnlockedDef().then(function () {
- return self.renderer.commitChanges(recordID || self.handle).then(function () {
+ var savingDef = $.Deferred();
+ this.savingDef = savingDef;
+
+ return this.mutex.getUnlockedDef()
+ .then(function () {
+ return self.renderer.commitChanges(recordID || self.handle);
+ })
+ .then(function () {
return self.mutex.exec(self._saveRecord.bind(self, recordID, options));
- });
- });
- return this.savingDef;
+ })
+ .then(savingDef.resolve.bind(savingDef))
+ .fail(savingDef.resolve.bind(savingDef));
},
/**
* @override
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 1bd0782bd36..3e20035734d 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -2480,7 +2480,7 @@ var BasicModel = AbstractModel.extend({
if (field.type === 'many2one' && !record.fieldsInfo[record.viewType][name].__no_fetch) {
var localId = (record._changes && record._changes[name]) || record.data[name];
var relatedRecord = self.localData[localId];
- if (!relatedRecord) {
+ if (!relatedRecord || relatedRecord.data.display_name) {
return;
}
toBeFetched.push({
diff --git a/addons/web/static/src/js/views/control_panel/search/search_bar.js b/addons/web/static/src/js/views/control_panel/search/search_bar.js
index 7f0feda4516..77d6d7fa5e9 100644
--- a/addons/web/static/src/js/views/control_panel/search/search_bar.js
+++ b/addons/web/static/src/js/views/control_panel/search/search_bar.js
@@ -142,6 +142,7 @@ var SearchBar = Widget.extend({
var self = this;
this._setupAutoCompletionWidgets();
this.autoComplete = new AutoComplete(this, {
+ $input: this.$('input'),
source: this._getAutoCompleteSources.bind(this),
select: this._onAutoCompleteSelected.bind(this),
get_search_string: function () {
diff --git a/addons/web/static/src/js/widgets/auto_complete.js b/addons/web/static/src/js/widgets/auto_complete.js
index 33405aa4196..6dd78f8f730 100644
--- a/addons/web/static/src/js/widgets/auto_complete.js
+++ b/addons/web/static/src/js/widgets/auto_complete.js
@@ -19,7 +19,7 @@ return Widget.extend({
// to obtain the current search string.
init: function (parent, options) {
this._super(parent);
- this.$input = parent.$el;
+ this.$input = options.$input;
this.source = options.source;
this.select = options.select;
this.get_search_string = options.get_search_string;
@@ -90,14 +90,24 @@ return Widget.extend({
ev.preventDefault();
break;
case $.ui.keyCode.RIGHT:
+ if(self.$input[0].selectionStart < self.search_string.length) {
+ ev.stopPropagation();
+ return;
+ }
self.searching = false;
var current = self.current_result;
if (current && current.expand && !current.expanded) {
self.expand();
self.searching = true;
+ ev.stopPropagation();
}
ev.preventDefault();
break;
+ case $.ui.keyCode.LEFT:
+ if(self.$input[0].selectionStart > 0) {
+ ev.stopPropagation();
+ }
+ break;
case $.ui.keyCode.ESCAPE:
self.close();
self.searching = false;
diff --git a/addons/web/static/src/scss/form_view.scss b/addons/web/static/src/scss/form_view.scss
index 697ec4dcd12..5642e656dea 100644
--- a/addons/web/static/src/scss/form_view.scss
+++ b/addons/web/static/src/scss/form_view.scss
@@ -378,8 +378,8 @@
clear: both; // For the notebook not to have alongside floating elements
margin-top: $o-form-spacing-unit * 2;
- .nav-tabs > .tab-pane {
- min-height: 100px;
+ .tab-content > .tab-pane {
+ padding: $o-horizontal-padding 0;
}
}
diff --git a/addons/web/static/src/scss/layout_background.scss b/addons/web/static/src/scss/layout_background.scss
index 9c47ac72a27..9b137fde8c1 100644
--- a/addons/web/static/src/scss/layout_background.scss
+++ b/addons/web/static/src/scss/layout_background.scss
@@ -18,6 +18,9 @@
}
}
.o_background_footer {
+ .list-inline-item {
+ white-space: nowrap;
+ }
ul {
border-top: 1px solid $o-brand-odoo;
border-bottom: 1px solid $o-brand-odoo;
diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss
index 770508ac1b8..85b9b9f6f07 100644
--- a/addons/web/static/src/scss/list_view.scss
+++ b/addons/web/static/src/scss/list_view.scss
@@ -52,7 +52,6 @@
}
&:not(:empty)::after {
margin-left: 6px;
- position: absolute;
}
&.o-sort-up {
cursor: n-resize;
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 463effad124..faf3df6f2e8 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -205,6 +205,42 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('do not call name_get if display_name already known', function (assert) {
+ // default_get only returns the id for many2one fields
+ // onchange returns an array with the id and the display_name
+ // thus, when an onchange is performed, there is no need to call
+ // name_get as the display_name is alreay available
+ assert.expect(6);
+
+ this.data.partner.fields.product_id.default = 37;
+ this.data.partner.onchanges = {
+ trululu: function (obj) {
+ obj.trululu = [1, 'first record'];
+ },
+ };
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form><field name="trululu"/><field name="product_id"/></form>',
+ mockRPC: function (route, args) {
+ assert.step(args.method + ' on ' + args.model);
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(form.$('.o_field_widget[name=trululu] input').val(), 'first record');
+ assert.strictEqual(form.$('.o_field_widget[name=product_id] input').val(), 'xphone');
+ assert.verifySteps([
+ 'default_get on partner',
+ 'onchange on partner',
+ 'name_get on product',
+ ]);
+
+ form.destroy();
+ });
+
QUnit.test('x2many default_order multiple fields', function (assert) {
assert.expect(7);
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index debba8d550c..9e0e7dc1e84 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -7,6 +7,7 @@ var Dialog = require('web.Dialog');
var fieldUtils = require('web.field_utils');
var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
+var time = require('web.time');
var session = require('web.session');
var createActionManager = testUtils.createActionManager;
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 480f42a3587..a8dc874a5ae 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -105,6 +105,14 @@ QUnit.module('Views', {
]
},
};
+
+ this.actions = [{
+ id: 1,
+ name: 'Partners Action 1',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'kanban'], [false, 'form']],
+ }];
}
}, function () {
@@ -7406,6 +7414,37 @@ QUnit.module('Views', {
form.destroy();
});
+ QUnit.test('discard after a failed save', function (assert) {
+ assert.expect(2);
+
+ var actionManager = createActionManager({
+ data: this.data,
+ archs: {
+ 'partner,false,form': '<form>' +
+ '<field name="date" required="true"/>' +
+ '<field name="foo" required="true"/>' +
+ '</form>',
+ 'partner,false,kanban': '<kanban><templates><t t-name="kanban-box">' +
+ '</t></templates></kanban>',
+ 'partner,false,search': '<search></search>',
+ },
+ actions: this.actions,
+ });
+
+ actionManager.doAction(1);
+
+ testUtils.dom.click('.o_control_panel .o-kanban-button-new');
+
+ //cannot save because there is a required field
+ testUtils.dom.click('.o_control_panel .o_form_button_save');
+ testUtils.dom.click('.o_control_panel .o_form_button_cancel');
+
+ assert.containsNone(actionManager, '.o_form_view');
+ assert.containsOnce(actionManager, '.o_kanban_view');
+
+ actionManager.destroy();
+ });
+
QUnit.test("one2many create record dialog shouldn't have a 'remove' button", function (assert) {
assert.expect(2);