summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-01-12 19:03:00 +0100
committerChristophe Simonis <chs@odoo.com>2018-01-12 19:03:00 +0100
commit56974322f8c67ec5680654ed4bcb08ca57117c46 (patch)
treee64c00274a47c46cf78e99b6ba62df4bc4dbbba4 /addons/web/static
parentf6ef0c776096774fc4c6821449ab42cfc2f53e62 (diff)
parent3b80a059ff4305fe10c9b40a3118508b1b849ead (diff)
[MERGE] forward port branch 11.0 up to 3b80a059ff4
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/js/core/utils.js18
-rw-r--r--addons/web/static/src/js/fields/abstract_field.js5
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js21
-rw-r--r--addons/web/static/src/js/fields/field_registry.js1
-rw-r--r--addons/web/static/src/js/fields/field_utils.js10
-rw-r--r--addons/web/static/src/js/services/data_manager.js4
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js45
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js11
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_controller.js19
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_renderer.js12
-rw-r--r--addons/web/static/src/xml/base.xml3
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js34
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js41
-rw-r--r--addons/web/static/tests/views/basic_model_tests.js1
-rw-r--r--addons/web/static/tests/views/form_tests.js35
-rw-r--r--addons/web/static/tests/views/kanban_tests.js95
16 files changed, 266 insertions, 89 deletions
diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js
index 99534708a94..1bdd9e70a69 100644
--- a/addons/web/static/src/js/core/utils.js
+++ b/addons/web/static/src/js/core/utils.js
@@ -24,6 +24,22 @@ var utils = {
}
},
/**
+ * Check if the value is a bin_size or not.
+ * If not, compute an approximate size out of the base64 encoded string.
+ *
+ * @param {string} value original format
+ * @return {string} bin_size (human-readable)
+ */
+ binaryToBinsize: function (value) {
+ if (!this.is_bin_size(value)) {
+ // Computing approximate size out of base64 encoded string
+ // http://en.wikipedia.org/wiki/Base64#MIME
+ return this.human_size(value.length / 1.37);
+ }
+ // already bin_size
+ return value;
+ },
+ /**
* Confines a value inside an interval
*
* @param {number} [val] the value to confine
@@ -132,7 +148,7 @@ var utils = {
size /= 1024;
++i;
}
- return size.toFixed(2) + ' ' + units[i];
+ return size.toFixed(2) + ' ' + units[i].trim();
},
/**
* Insert "thousands" separators in the provided number (which is actually
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js
index 2534f8ae90a..8bb9afca065 100644
--- a/addons/web/static/src/js/fields/abstract_field.js
+++ b/addons/web/static/src/js/fields/abstract_field.js
@@ -45,6 +45,11 @@ var AbstractField = Widget.extend({
},
/**
+ * fields can extend the context, e.g. binary fields add {bin_size: true}
+ */
+ context: null,
+
+ /**
* An object representing fields to be fetched by the model eventhough not present in the view
* This object contains "field name" as key and an object as value.
* That value object must contain the key "type"
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index d0662fe7cef..f3e66cee421 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -1094,6 +1094,7 @@ var AbstractFieldBinary = AbstractField.extend({
},
'click .o_clear_file_button': 'on_clear',
}),
+ context: { bin_size: true },
init: function (parent, name, record) {
this._super.apply(this, arguments);
this.fields = record.fields;
@@ -1312,25 +1313,6 @@ var FieldBinaryFile = AbstractFieldBinary.extend({
},
});
-var FieldBinaryDownloadLink = AbstractFieldBinary.extend({
- template: 'FieldBinaryDownloadLink',
- events: _.extend({}, AbstractFieldBinary.prototype.events, {
- 'click': function (ev) {
- ev.stopPropagation();
- },
- }),
- supportedFieldTypes: ['binary'],
- init: function () {
- this._super.apply(this, arguments);
- this.filename = _t("Binary File");
- if (this.nodeOptions.filename && this.recordData[this.nodeOptions.filename]) {
- this.filename = this.recordData[this.nodeOptions.filename];
- }
- this.url = "data:application/octet-stream;base64," + this.value;
- this.text = _t("Download");
- },
-});
-
var PriorityWidget = AbstractField.extend({
// the current implementation of this widget makes it
// only usable for fields of type selection
@@ -2561,7 +2543,6 @@ return {
TranslatableFieldMixin: TranslatableFieldMixin,
DebouncedField: DebouncedField,
FieldEmail: FieldEmail,
- FieldBinaryDownloadLink: FieldBinaryDownloadLink,
FieldBinaryFile: FieldBinaryFile,
FieldBinaryImage: FieldBinaryImage,
FieldBoolean: FieldBoolean,
diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js
index 85b4fc1187f..6692663d5f9 100644
--- a/addons/web/static/src/js/fields/field_registry.js
+++ b/addons/web/static/src/js/fields/field_registry.js
@@ -33,7 +33,6 @@ registry
.add('email', basic_fields.FieldEmail)
.add('phone', basic_fields.FieldPhone)
.add('url', basic_fields.UrlWidget)
- .add('download_link', basic_fields.FieldBinaryDownloadLink)
.add('image', basic_fields.FieldBinaryImage)
.add('binary', basic_fields.FieldBinaryFile)
.add('monetary', basic_fields.FieldMonetary)
diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js
index 812a7f380f7..5ac180b1de1 100644
--- a/addons/web/static/src/js/fields/field_utils.js
+++ b/addons/web/static/src/js/fields/field_utils.js
@@ -28,17 +28,17 @@ var _t = core._t;
//------------------------------------------------------------------------------
/**
+ * Convert binary to bin_size
*
- * @param {string} value base64 representation of the binary
+ * @param {string} value base64 representation of the binary (might be already a bin_size!)
* @param {Object} [field]
* a description of the field (note: this parameter is ignored)
* @param {Object} [options] additional options (note: this parameter is ignored)
+ *
+ * @returns {string} bin_size (which is human-readable)
*/
function formatBinary(value, field, options) {
- if (!value) {
- return '';
- }
- return utils.human_size(value.length / 1.37); // base64 estimated size: http://en.wikipedia.org/wiki/Base64#MIME
+ return utils.binaryToBinsize(value);
}
/**
diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js
index 72ec816efdd..948d3a1c73a 100644
--- a/addons/web/static/src/js/services/data_manager.js
+++ b/addons/web/static/src/js/services/data_manager.js
@@ -387,6 +387,10 @@ return core.Class.extend({
attrs.fieldDependencies = attrs.Widget.prototype.fieldDependencies;
}
+ if (attrs.Widget.prototype.context) {
+ attrs.context = attrs.Widget.prototype.context;
+ }
+
return attrs;
},
/**
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 3621b7c1227..a6979776c99 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -33,7 +33,7 @@ odoo.define('web.BasicModel', function (require) {
* isOpen: {boolean},
* loadMoreOffset: {integer},
* limit: {integer},
- * model: {string,
+ * model: {string},
* offset: {integer},
* openGroupByDefault: {boolean},
* orderedBy: {Object[]},
@@ -1854,7 +1854,7 @@ var BasicModel = AbstractModel.extend({
model: record.model,
method: 'read',
args: [[record.res_id], fieldNames],
- context: _.extend({}, record.getContext(), {bin_size: true}),
+ context: record.getContext(),
})
.then(function (result) {
if (result.length === 0) {
@@ -2374,7 +2374,7 @@ var BasicModel = AbstractModel.extend({
});
record.data[fieldName] = list.id;
if (!fieldInfo.__no_fetch) {
- var def = self._readUngroupedList(list).then(function () {
+ var def = self._readUngroupedList(list).then(function (list) {
return $.when(
self._fetchX2ManysBatched(list),
self._fetchReferencesBatched(list)
@@ -3040,10 +3040,33 @@ var BasicModel = AbstractModel.extend({
* the resource in the localData object.
*
* @param {Object} params
+ * @param {Object} [params.aggregateValues={}]
+ * @param {Object} [params.context={}] context of the action
+ * @param {integer} [params.count=0] number of record being manipulated
+ * @param {Object|Object[]} [params.data={}|[]] data of the record
+ * @param {*[]} [params.domain=[]]
+ * @param {Object} params.fields contains the description of each field
* @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field
- * @param {Array} [params.fieldNames] the name of fields to load, the list
+ * @param {Object[]} [params.fieldNames] the name of fields to load, the list
* of all fields by default
- * @param {Object} params.fields contains the description of each field
+ * @param {string[]} [params.groupedBy=[]]
+ * @param {boolean} [params.isOpen]
+ * @param {integer} params.limit max number of records shown on screen (pager size)
+ * @param {string} params.modelName
+ * @param {integer} [params.offset]
+ * @param {boolean} [params.openGroupByDefault]
+ * @param {Object[]} [params.orderedBy=[]]
+ * @param {integer[]} [params.orderedResIDs]
+ * @param {string} [params.parentID] model name ID of the parent model
+ * @param {Object} [params.rawContext]
+ * @param {[type]} [params.ref]
+ * @param {string} [params.relationField]
+ * @param {integer|null} [params.res_id] actual id of record in the server
+ * @param {integer[]} [params.res_ids] context in which the data point is used, from a list of res_id
+ * @param {boolean} [params.static=false]
+ * @param {string} [params.type='record'|'list']
+ * @param {[type]} [params.value]
+ * @param {string} [params.viewType] the type of the view, e.g. 'list' or 'form'
* @returns {Object} the resource created
*/
_makeDataPoint: function (params) {
@@ -3069,13 +3092,23 @@ var BasicModel = AbstractModel.extend({
id: {type: 'integer'},
}, params.fields);
+ // datapoint context is extended by fields widgets
+ var context = _.extend({}, params.context);
+ if (params.fieldsInfo && params.viewType) {
+ _.each(params.fieldsInfo[params.viewType], function (field) {
+ if (field.context) {
+ _.extend(context, field.context);
+ }
+ });
+ }
+
var dataPoint = {
_cache: type === 'list' ? {} : undefined,
_changes: null,
_domains: {},
_rawChanges: {},
aggregateValues: params.aggregateValues || {},
- context: params.context || {},
+ context: context,
count: params.count || res_ids.length,
data: data,
domain: params.domain || [],
diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js
index 9409a51b7e0..779121de3e9 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -693,6 +693,7 @@ var FormRenderer = BasicRenderer.extend({
var self = this;
var $headers = $('<ul class="nav nav-tabs">');
var $pages = $('<div class="tab-content nav nav-tabs">');
+ var autofocusTab = -1;
// renderedTabs is used to aggregate the generated $headers and $pages
// alongside their node, so that their modifiers can be registered once
// all tabs have been rendered, to ensure that the first visible tab
@@ -701,9 +702,8 @@ var FormRenderer = BasicRenderer.extend({
var pageID = _.uniqueId('notebook_page_');
var $header = self._renderTabHeader(child, pageID);
var $page = self._renderTabPage(child, pageID);
- if (index === 0) {
- $header.addClass('active');
- $page.addClass('active');
+ if (autofocusTab === -1 && child.attrs.autofocus === 'autofocus') {
+ autofocusTab = index;
}
self._handleAttributes($header, child);
$headers.append($header);
@@ -714,6 +714,11 @@ var FormRenderer = BasicRenderer.extend({
node: child,
};
});
+ if (renderedTabs.length) {
+ var tabToFocus = renderedTabs[Math.max(0, autofocusTab)];
+ tabToFocus.$header.addClass('active');
+ tabToFocus.$page.addClass('active');
+ }
// register the modifiers for each tab
_.each(renderedTabs, function (tab) {
self._registerModifiers(tab.node, self.state, tab.$header, {
diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js
index 2f6f566649e..9e97ec40686 100644
--- a/addons/web/static/src/js/views/kanban/kanban_controller.js
+++ b/addons/web/static/src/js/views/kanban/kanban_controller.js
@@ -239,15 +239,16 @@ var KanbanController = BasicController.extend({
* @private
*/
_onButtonNew: function () {
- var data = this.model.get(this.handle, {raw: true});
- if (data.groupedBy.length > 0 && data.count > 0 && this.on_create === 'quick_create') {
+ var state = this.model.get(this.handle, {raw: true});
+ var hasColumns = state.groupedBy.length > 0 && state.data.length > 0;
+ if (hasColumns && this.on_create === 'quick_create') {
// Activate the quick create in the first column
this.renderer.addQuickCreate();
} else if (this.on_create && this.on_create !== 'quick_create') {
// Execute the given action
this.do_action(this.on_create, {
on_close: this.reload.bind(this),
- additional_context: data.context,
+ additional_context: state.context,
});
} else {
// Open the form view
@@ -355,11 +356,13 @@ var KanbanController = BasicController.extend({
self._updateEnv();
var columnState = self.model.getColumn(db_id);
- return self.renderer.updateColumn(columnState.id, columnState).then(function () {
- if (event.data.openRecord) {
- self.trigger_up('open_record', {id: db_id, mode: 'edit'});
- }
- });
+ return self.renderer
+ .updateColumn(columnState.id, columnState, {openQuickCreate: true})
+ .then(function () {
+ if (event.data.openRecord) {
+ self.trigger_up('open_record', {id: db_id, mode: 'edit'});
+ }
+ });
});
}
},
diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js
index 0f91fb2ae14..e4e37095afa 100644
--- a/addons/web/static/src/js/views/kanban/kanban_renderer.js
+++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js
@@ -141,15 +141,23 @@ var KanbanRenderer = BasicRenderer.extend({
*
* @param {string} localID the column id
* @param {Object} columnState
+ * @param {Object} [options]
+ * @param {boolean} [options.openQuickCreate] if true, directly opens the
+ * QuickCreate widget in the updated column
*
* @returns {Deferred}
*/
- updateColumn: function (localID, columnState) {
+ updateColumn: function (localID, columnState, options) {
var newColumn = new KanbanColumn(this, columnState, this.columnOptions, this.recordOptions);
var index = _.findIndex(this.widgets, {db_id: localID});
var column = this.widgets[index];
this.widgets[index] = newColumn;
- return newColumn.insertAfter(column.$el).then(column.destroy.bind(column));
+ return newColumn.insertAfter(column.$el).then(function () {
+ if (options && options.openQuickCreate) {
+ newColumn.addQuickCreate();
+ }
+ column.destroy();
+ });
},
/**
* Updates a given record with its new state.
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 8ee6f643c51..509c03fdf4b 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -906,9 +906,6 @@
</t>
</div>
</t>
-<t t-name="FieldBinaryDownloadLink">
- <a t-att-download="widget.filename" t-att-href="widget.url"><t t-esc="widget.text"/></a>
-</t>
<t t-name="HiddenInputFile">
<div t-attf-class="o_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style">
<form class="o_form_binary_form" t-att-target="fileupload_id"
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 97601c8e6d0..4fd9d6ee84e 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -1518,40 +1518,6 @@ QUnit.module('basic_fields', {
session.get_file = oldGetFile;
});
- QUnit.test('download_link widget in list view', function (assert) {
- assert.expect(5);
-
- this.data.partner.fields.filename = { string: "Filename", type: "char" };
- this.data.partner.records[0].filename = "document.txt";
-
- var form = createView({
- View: ListView,
- model: 'partner',
- data: this.data,
- arch: '<tree string="Partners">' +
- '<field name="document" widget="download_link" options="{\'filename\': \'filename\'}"/>' +
- '<field name="filename"/>' +
- '</tree>',
- res_id: 1,
- });
-
- assert.ok(form.$('.o_data_cell').first().hasClass("o_download_link_cell"),
- "this should be a download link cell");
- assert.ok(form.$('.o_data_cell').first().find('a').eq(0),
- "there should be a link in the cell");
- assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).attr('download'),
- "document.txt",
- "it should download a file named 'document.txt'");
- assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).attr('href').trim(),
- "data:application/octet-stream;base64,coucou==",
- "it should have the appropriate link of a binary");
- assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).text(),
- "Download",
- "the text of the link should be 'Download'");
-
- form.destroy();
- });
-
QUnit.test('text field rendering in list view', function (assert) {
assert.expect(1);
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index c149b5c3dba..ef5139511fe 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -6916,7 +6916,6 @@ QUnit.module('relational_fields', {
if (args.method === 'read' && args.model === 'partner') {
assert.deepEqual(args.kwargs.context, {
active_field: 2,
- bin_size: true,
someKey: 'some value',
}, "sent context should be correct");
}
@@ -7600,6 +7599,46 @@ QUnit.module('relational_fields', {
form.destroy();
});
+
+ QUnit.test('one2many with multiple pages and sequence field', function (assert) {
+ assert.expect(1);
+
+ this.data.partner.records[0].turtles = [3, 2, 1];
+ this.data.partner.onchanges.turtles = function () {};
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="turtles">' +
+ '<tree limit="2">' +
+ '<field name="turtle_int" widget="handle"/>' +
+ '<field name="turtle_foo"/>' +
+ '<field name="partner_ids" invisible="1"/>' +
+ '</tree>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ return $.when({value: { turtles: [
+ [5],
+ [1, 1, {turtle_foo: "from onchange", partner_ids: [[5]]}],
+ ]}});
+ }
+ return this._super(route, args);
+ },
+ viewOptions: {
+ mode: 'edit',
+ },
+ });
+ form.$('span[name="delete"]').first().click();
+ assert.strictEqual(form.$('.o_data_row').text(), 'from onchange',
+ 'onchange has been properly applied');
+ form.destroy();
+ });
+
QUnit.module('FieldMany2Many');
QUnit.test('many2many kanban: edition', function (assert) {
diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js
index 492dfd4224c..72061f326e0 100644
--- a/addons/web/static/tests/views/basic_model_tests.js
+++ b/addons/web/static/tests/views/basic_model_tests.js
@@ -74,7 +74,6 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
assert.deepEqual(args.kwargs.context, {
active_field: 2,
- bin_size: true,
someKey: 'some value',
}, "should have sent the correct context");
return this._super.apply(this, arguments);
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 1f5e57b2202..9f2a9b68698 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -199,7 +199,7 @@ QUnit.module('Views', {
});
QUnit.test('only necessary fields are fetched with correct context', function (assert) {
- assert.expect(2);
+ assert.expect(1);
var form = createView({
View: FormView,
@@ -214,8 +214,6 @@ QUnit.module('Views', {
// field, not sure why. Maybe this test should be modified.
assert.deepEqual(args.args[1], ["foo", "display_name"],
"should only fetch requested fields");
- assert.deepEqual(args.kwargs.context, {bin_size: true},
- "bin_size should always be in the context");
return this._super(route, args);
}
});
@@ -483,6 +481,37 @@ QUnit.module('Views', {
form.destroy();
});
+ QUnit.test('autofocus on second notebook page', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<field name="product_id"/>' +
+ '<notebook>' +
+ '<page string="Choucroute">' +
+ '<field name="foo"/>' +
+ '</page>' +
+ '<page string="Cassoulet" autofocus="autofocus">' +
+ '<field name="bar"/>' +
+ '</page>' +
+ '</notebook>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ assert.notOk(form.$('.o_notebook .nav li:first()').hasClass('active'),
+ 'first tab should not active');
+ assert.ok(form.$('.o_notebook .nav li:nth(1)').hasClass('active'),
+ 'second tab should be active');
+
+ form.destroy();
+ });
+
QUnit.test('invisible attrs on group are re-evaluated on field change', function (assert) {
assert.expect(2);
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index 9c8361e63ae..9e6d6e9e30f 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -493,6 +493,58 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('quick create several records in a row', function (assert) {
+ assert.expect(6);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<field name="bar"/>' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="foo"/></div>' +
+ '</t></templates></kanban>',
+ groupBy: ['bar'],
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "first column should contain one record");
+
+ // click to add an element, fill the input and press ENTER
+ kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
+
+ assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
+ "the quick create should be open");
+
+ kanban.$('.o_kanban_quick_create input')
+ .val('new partner 1')
+ .trigger($.Event('keypress', {
+ which: $.ui.keyCode.ENTER,
+ keyCode: $.ui.keyCode.ENTER,
+ }));
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
+ "first column should now contain two records");
+ assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
+ "the quick create should still be open");
+
+ // create a second element in a row
+ kanban.$('.o_kanban_quick_create input')
+ .val('new partner 2')
+ .trigger($.Event('keypress', {
+ which: $.ui.keyCode.ENTER,
+ keyCode: $.ui.keyCode.ENTER,
+ }));
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3,
+ "first column should now contain three records");
+ assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
+ "the quick create should still be open");
+
+ kanban.destroy();
+ });
+
QUnit.test('quick create fail in grouped', function (assert) {
assert.expect(7);
@@ -524,7 +576,6 @@ QUnit.module('Views', {
return this._super.apply(this, arguments);
},
});
- kanban.renderButtons();
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
"there should be 2 records in first column");
@@ -556,6 +607,48 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('quick create record in empty grouped kanban', function (assert) {
+ assert.expect(3);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban on_create="quick_create">' +
+ '<field name="product_id"/>' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="foo"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['product_id'],
+ mockRPC: function (route, args) {
+ if (args.method === 'read_group') {
+ // override read_group to return empty groups, as this is
+ // the case for several models (e.g. project.task grouped
+ // by stage_id)
+ var result = [
+ {__domain: [['product_id', '=', 3]], product_id_count: 0},
+ {__domain: [['product_id', '=', 5]], product_id_count: 0},
+ ];
+ return $.when(result);
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_group').length, 2,
+ "there should be 2 columns");
+ assert.strictEqual(kanban.$('.o_kanban_record').length, 0,
+ "both columns should be empty");
+
+ kanban.$buttons.find('.o-kanban-button-new').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_quick_create').length, 1,
+ "should have opened the quick create in the first column");
+
+ kanban.destroy();
+ });
+
QUnit.test('many2many_tags in kanban views', function (assert) {
assert.expect(12);