[MERGE] some others fixes from 7.0
bzr revid: nicolas.vanhoren@openerp.com-20130227141209-kemu3v78npynip87 bzr revid: nicolas.vanhoren@openerp.com-20130227142021-oc8i22kpfgmgv9jh
This commit is contained in:
commit
d04d532201
|
@ -1084,7 +1084,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
|
|||
if (!self.session.uid)
|
||||
return;
|
||||
var func = new instance.web.Model("res.users").get_func("read");
|
||||
return func(self.session.uid, ["name", "company_id"]).then(function(res) {
|
||||
return self.alive(func(self.session.uid, ["name", "company_id"])).then(function(res) {
|
||||
var topbar_name = res.name;
|
||||
if(instance.session.debug)
|
||||
topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db);
|
||||
|
@ -1303,7 +1303,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
|||
},
|
||||
logo_edit: function(ev) {
|
||||
var self = this;
|
||||
new instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"]).then(function(res) {
|
||||
new self.alive(instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"])).then(function(res) {
|
||||
self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
|
||||
result.res_id = res['company_id'][0];
|
||||
result.target = "new";
|
||||
|
@ -1324,7 +1324,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
|||
},
|
||||
check_timezone: function() {
|
||||
var self = this;
|
||||
return new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']]).then(function(result) {
|
||||
return self.alive(new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']])).then(function(result) {
|
||||
var user_offset = result[0]['tz_offset'];
|
||||
var offset = -(new Date().getTimezoneOffset());
|
||||
// _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually
|
||||
|
|
|
@ -228,6 +228,38 @@ instance.web.ParentedMixin = {
|
|||
isDestroyed : function() {
|
||||
return this.__parentedDestroyed;
|
||||
},
|
||||
/**
|
||||
Utility method to only execute asynchronous actions if the current
|
||||
object has not been destroyed.
|
||||
|
||||
@param {Promise} promise The promise representing the asynchronous action.
|
||||
@param {bool} reject Defaults to false. If true, the returned promise will be
|
||||
rejected with no arguments if the current object is destroyed. If false,
|
||||
the returned promise will never be resolved nor rejected.
|
||||
@returns {Promise} A promise that will mirror the given promise if everything goes
|
||||
fine but will either be rejected with no arguments or never resolved if the
|
||||
current object is destroyed.
|
||||
*/
|
||||
alive: function(promise, reject) {
|
||||
var def = $.Deferred();
|
||||
var self = this;
|
||||
promise.done(function() {
|
||||
if (! self.isDestroyed()) {
|
||||
if (! reject)
|
||||
def.resolve.apply(def, arguments);
|
||||
else
|
||||
def.reject();
|
||||
}
|
||||
}).fail(function() {
|
||||
if (! self.isDestroyed()) {
|
||||
if (! reject)
|
||||
def.reject.apply(def, arguments);
|
||||
else
|
||||
def.reject();
|
||||
}
|
||||
});
|
||||
return def.promise();
|
||||
},
|
||||
/**
|
||||
* Inform the object it should destroy itself, releasing any
|
||||
* resource it could have reserved.
|
||||
|
@ -495,16 +527,7 @@ instance.web.Controller = instance.web.Class.extend(instance.web.PropertiesMixin
|
|||
return false;
|
||||
},
|
||||
rpc: function(url, data, options) {
|
||||
var def = $.Deferred();
|
||||
var self = this;
|
||||
instance.session.rpc(url, data, options).done(function() {
|
||||
if (!self.isDestroyed())
|
||||
def.resolve.apply(def, arguments);
|
||||
}).fail(function() {
|
||||
if (!self.isDestroyed())
|
||||
def.reject.apply(def, arguments);
|
||||
});
|
||||
return def.promise();
|
||||
return this.alive(instance.session.rpc(url, data, options));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1466,12 +1466,15 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
|
|||
},
|
||||
complete: function (needle) {
|
||||
var self = this;
|
||||
// TODO: context
|
||||
// FIXME: "concurrent" searches (multiple requests, mis-ordered responses)
|
||||
var context = instance.web.pyeval.eval(
|
||||
'contexts', [this.view.dataset.get_context()]);
|
||||
return this.model.call('name_search', [], {
|
||||
name: needle,
|
||||
args: instance.web.pyeval.eval(
|
||||
'domains', this.attrs.domain ? [this.attrs.domain] : [], context),
|
||||
limit: 8,
|
||||
context: {}
|
||||
context: context
|
||||
}).then(function (results) {
|
||||
if (_.isEmpty(results)) { return null; }
|
||||
return [{label: self.attrs.string}].concat(
|
||||
|
|
|
@ -247,7 +247,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
|
||||
do_load_state: function(state, warm) {
|
||||
if (state.id && this.datarecord.id != state.id) {
|
||||
if (!this.dataset.get_id_index(state.id)) {
|
||||
if (this.dataset.get_id_index(state.id) === null) {
|
||||
this.dataset.ids.push(state.id);
|
||||
}
|
||||
this.dataset.select_id(state.id);
|
||||
|
@ -514,8 +514,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
// In case of a o2m virtual id, we should pass an empty ids list
|
||||
ids.push(self.datarecord.id);
|
||||
}
|
||||
def = new instance.web.Model(self.dataset.model).call(
|
||||
change_spec.method, [ids].concat(change_spec.args));
|
||||
def = self.alive(new instance.web.Model(self.dataset.model).call(
|
||||
change_spec.method, [ids].concat(change_spec.args)));
|
||||
} else {
|
||||
def = $.when({});
|
||||
}
|
||||
|
@ -533,9 +533,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
var condition = fieldname + '=' + value_;
|
||||
|
||||
if (value_) {
|
||||
return new instance.web.Model('ir.values').call(
|
||||
return self.alive(new instance.web.Model('ir.values').call(
|
||||
'get_defaults', [self.model, condition]
|
||||
).then(function (results) {
|
||||
)).then(function (results) {
|
||||
if (!results.length) {
|
||||
return response;
|
||||
}
|
||||
|
@ -1193,6 +1193,10 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
|
|||
$('button', doc).each(function() {
|
||||
$(this).attr('data-button-type', $(this).attr('type')).attr('type', 'button');
|
||||
});
|
||||
// IE's html parser is also a css parser. How convenient...
|
||||
$('board', doc).each(function() {
|
||||
$(this).attr('layout', $(this).attr('style'));
|
||||
});
|
||||
return $('<div class="oe_form"/>').append(instance.web.xml_to_str(doc));
|
||||
},
|
||||
render_to: function($target) {
|
||||
|
@ -2329,7 +2333,7 @@ instance.web.form.FieldUrl = instance.web.form.FieldChar.extend({
|
|||
this._super();
|
||||
} else {
|
||||
var tmp = this.get('value');
|
||||
var s = /(\w+):(.+)/.exec(tmp);
|
||||
var s = /(\w+):(.+)|^\.{0,2}\//.exec(tmp);
|
||||
if (!s) {
|
||||
tmp = "http://" + this.get('value');
|
||||
}
|
||||
|
@ -2398,6 +2402,11 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
|
|||
showButtonPanel: true,
|
||||
firstDay: Date.CultureInfo.firstDayOfWeek
|
||||
});
|
||||
// Some clicks in the datepicker dialog are not stopped by the
|
||||
// datepicker and "bubble through", unexpectedly triggering the bus's
|
||||
// click event. Prevent that.
|
||||
this.picker('widget').click(function (e) { e.stopPropagation(); });
|
||||
|
||||
this.$el.find('img.oe_datepicker_trigger').click(function() {
|
||||
if (self.get("effective_readonly") || self.picker('widget').is(':visible')) {
|
||||
self.$input.focus();
|
||||
|
@ -3063,6 +3072,15 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Autocomplete close on dialog content scroll
|
||||
var close_autocomplete = _.debounce(function() {
|
||||
if (self.$input.autocomplete("widget").is(":visible")) {
|
||||
self.$input.autocomplete("close");
|
||||
}
|
||||
}, 50);
|
||||
this.$input.closest(".ui-dialog .ui-dialog-content").on('scroll', this, close_autocomplete);
|
||||
|
||||
self.ed_def = $.Deferred();
|
||||
self.uned_def = $.Deferred();
|
||||
var ed_delay = 200;
|
||||
|
@ -5230,10 +5248,20 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
this.options.clickable = this.options.clickable || (this.node.attrs || {}).clickable || false;
|
||||
this.options.visible = this.options.visible || (this.node.attrs || {}).statusbar_visible || false;
|
||||
this.set({value: false});
|
||||
this.field_manager.on("view_content_has_changed", this, this.render_value);
|
||||
this.selection_mutex = new $.Mutex();
|
||||
this.selection = [];
|
||||
this.set("selection", []);
|
||||
this.selection_dm = new instance.web.DropMisordered();
|
||||
},
|
||||
start: function() {
|
||||
this.field_manager.on("view_content_has_changed", this, this.calc_domain);
|
||||
this.calc_domain();
|
||||
this.on("change:value", this, this.get_selection);
|
||||
this.on("change:evaluated_selection_domain", this, this.get_selection);
|
||||
this.get_selection();
|
||||
this.on("change:selection", this, function() {
|
||||
this.selection = this.get("selection");
|
||||
this.render_value();
|
||||
});
|
||||
if (this.options.clickable) {
|
||||
this.$el.on('click','li',this.on_click_stage);
|
||||
}
|
||||
|
@ -5250,8 +5278,6 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
},
|
||||
render_value: function() {
|
||||
var self = this;
|
||||
self.selection_mutex.exec(function() {
|
||||
return self.get_selection().done(function() {
|
||||
var content = QWeb.render("FieldStatus.content", {widget: self});
|
||||
self.$el.html(content);
|
||||
var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}");
|
||||
|
@ -5259,8 +5285,13 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
if (color) {
|
||||
self.$("oe_active").css("color", color);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
calc_domain: function() {
|
||||
var d = instance.web.pyeval.eval('domain', this.build_domain());
|
||||
domain = ['|', ['id', '=', this.get('value')]].concat(d);
|
||||
if (! _.isEqual(domain, this.get("evaluated_selection_domain"))) {
|
||||
this.set("evaluated_selection_domain", domain);
|
||||
}
|
||||
},
|
||||
/** Get the selection and render it
|
||||
* selection: [[identifier, value_to_display], ...]
|
||||
|
@ -5269,32 +5300,37 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
*/
|
||||
get_selection: function() {
|
||||
var self = this;
|
||||
self.selection = [];
|
||||
var selection = [];
|
||||
|
||||
var calculation = _.bind(function() {
|
||||
if (this.field.type == "many2one") {
|
||||
var domain = [];
|
||||
if(!_.isEmpty(this.field.domain) || !_.isEmpty(this.node.attrs.domain)) {
|
||||
var d = instance.web.pyeval.eval('domain', self.build_domain());
|
||||
domain = ['|', ['id', '=', self.get('value')]].concat(d);
|
||||
}
|
||||
var ds = new instance.web.DataSetSearch(this, this.field.relation, self.build_context(), domain);
|
||||
var ds = new instance.web.DataSetSearch(this, this.field.relation,
|
||||
self.build_context(), this.get("evaluated_selection_domain"));
|
||||
return ds.read_slice(['name'], {}).then(function (records) {
|
||||
for(var i = 0; i < records.length; i++) {
|
||||
self.selection.push([records[i].id, records[i].name]);
|
||||
selection.push([records[i].id, records[i].name]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For field type selection filter values according to
|
||||
// statusbar_visible attribute of the field. For example:
|
||||
// statusbar_visible="draft,open".
|
||||
var selection = this.field.selection;
|
||||
for(var i=0; i < selection.length; i++) {
|
||||
var key = selection[i][0];
|
||||
var select = this.field.selection;
|
||||
for(var i=0; i < select.length; i++) {
|
||||
var key = select[i][0];
|
||||
if(key == this.get('value') || !this.options.visible || this.options.visible.indexOf(key) != -1) {
|
||||
this.selection.push(selection[i]);
|
||||
selection.push(select[i]);
|
||||
}
|
||||
}
|
||||
return $.when();
|
||||
}
|
||||
}, this);
|
||||
this.selection_dm.add(calculation()).then(function () {
|
||||
if (! _.isEqual(selection, self.get("selection"))) {
|
||||
self.set("selection", selection);
|
||||
}
|
||||
});
|
||||
},
|
||||
on_click_stage: function (ev) {
|
||||
var self = this;
|
||||
|
@ -5338,8 +5374,8 @@ instance.web.form.FieldMonetary = instance.web.form.FieldFloat.extend({
|
|||
this.set({"currency_info": null});
|
||||
return;
|
||||
}
|
||||
return this.ci_dm.add(new instance.web.Model("res.currency").query(["symbol", "position"])
|
||||
.filter([["id", "=", self.get("currency")]]).first()).then(function(res) {
|
||||
return this.ci_dm.add(self.alive(new instance.web.Model("res.currency").query(["symbol", "position"])
|
||||
.filter([["id", "=", self.get("currency")]]).first())).then(function(res) {
|
||||
self.set({"currency_info": res});
|
||||
});
|
||||
},
|
||||
|
|
|
@ -2212,7 +2212,7 @@ instance.web.list.Binary = instance.web.list.Column.extend({
|
|||
if (value && value.substr(0, 10).indexOf(' ') == -1) {
|
||||
download_url = "data:application/octet-stream;base64," + value;
|
||||
} else {
|
||||
download_url = this.session.url('/web/binary/saveas', {model: options.model, field: this.id, id: options.id});
|
||||
download_url = instance.session.url('/web/binary/saveas', {model: options.model, field: this.id, id: options.id});
|
||||
if (this.filename) {
|
||||
download_url += '&filename_field=' + this.filename;
|
||||
}
|
||||
|
|
|
@ -132,6 +132,15 @@ openerp.web.list_editable = function (instance) {
|
|||
var self = this;
|
||||
// tree/@editable takes priority on everything else if present.
|
||||
var result = this._super(data, grouped);
|
||||
|
||||
// In case current editor was started previously, also has to run
|
||||
// when toggling from editable to non-editable in case form widgets
|
||||
// have setup global behaviors expecting themselves to exist
|
||||
// somehow.
|
||||
this.editor.destroy();
|
||||
// Editor is not restartable due to formview not being restartable
|
||||
this.editor = this.make_editor();
|
||||
|
||||
if (this.editable()) {
|
||||
this.$el.addClass('oe_list_editable');
|
||||
// FIXME: any hook available to ensure this is only done once?
|
||||
|
@ -143,10 +152,6 @@ openerp.web.list_editable = function (instance) {
|
|||
e.preventDefault();
|
||||
self.cancel_edition();
|
||||
});
|
||||
this.editor.destroy();
|
||||
// Editor is not restartable due to formview not being
|
||||
// restartable
|
||||
this.editor = this.make_editor();
|
||||
var editor_ready = this.editor.prependTo(this.$el)
|
||||
.done(this.proxy('setup_events'));
|
||||
|
||||
|
|
|
@ -1547,13 +1547,22 @@ instance.web.json_node_to_xml = function(node, human_readable, indent) {
|
|||
}
|
||||
};
|
||||
instance.web.xml_to_str = function(node) {
|
||||
var str = "";
|
||||
if (window.XMLSerializer) {
|
||||
return (new XMLSerializer()).serializeToString(node);
|
||||
str = (new XMLSerializer()).serializeToString(node);
|
||||
} else if (window.ActiveXObject) {
|
||||
return node.xml;
|
||||
str = node.xml;
|
||||
} else {
|
||||
throw new Error(_t("Could not serialize XML"));
|
||||
}
|
||||
// Browsers won't deal with self closing tags except br, hr, input, ...
|
||||
// http://stackoverflow.com/questions/97522/what-are-all-the-valid-self-closing-elements-in-xhtml-as-implemented-by-the-maj
|
||||
//
|
||||
// The following regex is a bit naive but it's ok for the xmlserializer output
|
||||
str = str.replace(/<([a-z]+)([^<>]*)\s*\/\s*>/g, function(match, tag, attrs) {
|
||||
return "<" + tag + attrs + "></" + tag + ">";
|
||||
});
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><label for="db_name">New database name:</label></td>
|
||||
<td><input type="text" name="db_name" class="required" matches="^[a-zA-Z][a-zA-Z0-9_-]+$" autofocus="true"/></td>
|
||||
<td><input type="text" name="db_name" class="required" matches="^[a-zA-Z0-9][a-zA-Z0-9_-]+$" autofocus="true"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="demo_data">Load Demonstration data:</label></td>
|
||||
|
@ -1300,7 +1300,7 @@
|
|||
<span class='oe_attach_label'>File</span>
|
||||
<t t-call="HiddenInputFile">
|
||||
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
|
||||
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<input type="hidden" name="model" t-att-value="widget.view.model"/>
|
||||
<input type="hidden" name="id" value="0"/>
|
||||
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
|
||||
|
|
|
@ -318,6 +318,28 @@ openerp.testing.section('defaults', {
|
|||
"facet value should match provided default's selection");
|
||||
});
|
||||
});
|
||||
test("M2O default: value array", {asserts: 2}, function (instance, $s, mock) {
|
||||
var view = {inputs: []}, id = 5;
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
{attrs: {name: 'dummy', string: 'Dummy'}},
|
||||
{relation: 'dummy.model.name'},
|
||||
view);
|
||||
mock('dummy.model.name:name_get', function (args) {
|
||||
equal(args[0], id);
|
||||
return [[id, "DumDumDum"]];
|
||||
});
|
||||
return f.facet_for_defaults({dummy: [id]})
|
||||
.done(function (facet) {
|
||||
var model = facet;
|
||||
if (!(model instanceof instance.web.search.Facet)) {
|
||||
model = new instance.web.search.Facet(facet);
|
||||
}
|
||||
deepEqual(
|
||||
model.values.toJSON(),
|
||||
[{label: "DumDumDum", value: id}],
|
||||
"should support default as a singleton");
|
||||
});
|
||||
});
|
||||
test("M2O default: value", {asserts: 1}, function (instance, $s, mock) {
|
||||
var view = {inputs: []}, id = 4;
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
|
@ -330,6 +352,15 @@ openerp.testing.section('defaults', {
|
|||
ok(!facet, "an invalid m2o default should yield a non-facet");
|
||||
});
|
||||
});
|
||||
test("M2O default: values", {rpc: false}, function (instance) {
|
||||
var view = {inputs: []};
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
{attrs: {name: 'dummy', string: 'Dummy'}},
|
||||
{relation: 'dummy.model.name'},
|
||||
view);
|
||||
raises(function () { f.facet_for_defaults({dummy: [6, 7]}) },
|
||||
"should not accept multiple default values");
|
||||
})
|
||||
});
|
||||
openerp.testing.section('completions', {
|
||||
dependencies: ['web.search'],
|
||||
|
@ -526,7 +557,7 @@ openerp.testing.section('completions', {
|
|||
return [[42, "choice 1"], [43, "choice @"]];
|
||||
});
|
||||
|
||||
var view = {inputs: []};
|
||||
var view = {inputs: [], dataset: {get_context: function () {}}};
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
|
||||
return f.complete("bob")
|
||||
|
@ -555,7 +586,7 @@ openerp.testing.section('completions', {
|
|||
strictEqual(kwargs.name, 'bob');
|
||||
return [];
|
||||
});
|
||||
var view = {inputs: []};
|
||||
var view = {inputs: [], dataset: {get_context: function () {}}};
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
|
||||
return f.complete("bob")
|
||||
|
@ -563,6 +594,26 @@ openerp.testing.section('completions', {
|
|||
ok(!c, "no match should yield no completion");
|
||||
});
|
||||
});
|
||||
test("M2O filtered", {asserts: 2}, function (instance, $s, mock) {
|
||||
mock('dummy.model:name_search', function (args, kwargs) {
|
||||
deepEqual(args, [], "should have no positional arguments");
|
||||
deepEqual(kwargs, {
|
||||
name: 'bob',
|
||||
limit: 8,
|
||||
args: [['foo', '=', 'bar']],
|
||||
context: {flag: 1},
|
||||
}, "should use filtering domain");
|
||||
return [[42, "Match"]];
|
||||
});
|
||||
var view = {
|
||||
inputs: [],
|
||||
dataset: {get_context: function () { return {flag: 1}; }}
|
||||
};
|
||||
var f = new instance.web.search.ManyToOneField(
|
||||
{attrs: {string: 'Dummy', domain: '[["foo", "=", "bar"]]'}},
|
||||
{relation: 'dummy.model'}, view);
|
||||
return f.complete("bob");
|
||||
});
|
||||
});
|
||||
openerp.testing.section('search-serialization', {
|
||||
dependencies: ['web.search'],
|
||||
|
|
|
@ -24,8 +24,8 @@ instance.web_gantt.GanttView = instance.web.View.extend({
|
|||
var self = this;
|
||||
this.fields_view = fields_view_get;
|
||||
this.$el.addClass(this.fields_view.arch.attrs['class']);
|
||||
return new instance.web.Model(this.dataset.model)
|
||||
.call('fields_get').then(function (fields) {
|
||||
return self.alive(new instance.web.Model(this.dataset.model)
|
||||
.call('fields_get')).then(function (fields) {
|
||||
self.fields = fields;
|
||||
self.has_been_loaded.resolve();
|
||||
});
|
||||
|
|
|
@ -246,7 +246,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
var result = [];
|
||||
var ticks = {};
|
||||
|
||||
return obj.call("fields_view_get", [view_id, 'graph']).then(function(tmp) {
|
||||
return this.alive(obj.call("fields_view_get", [view_id, 'graph']).then(function(tmp) {
|
||||
view_get = tmp;
|
||||
fields = view_get['fields'];
|
||||
var toload = _.select(group_by, function(x) { return fields[x] === undefined });
|
||||
|
@ -368,7 +368,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
'ticks': _.map(ticks, function(el, key) { return [el, key] })
|
||||
};
|
||||
return res;
|
||||
});
|
||||
}));
|
||||
},
|
||||
|
||||
// Render the graph and update menu styles
|
||||
|
|
|
@ -237,7 +237,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
|
|||
self.$el.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o);
|
||||
var grouping_fields = self.group_by ? [self.group_by].concat(_.keys(self.aggregates)) : undefined;
|
||||
var grouping = new instance.web.Model(self.dataset.model, context, domain).query().group_by(grouping_fields);
|
||||
return $.when(grouping).done(function(groups) {
|
||||
return self.alive($.when(grouping)).done(function(groups) {
|
||||
if (groups) {
|
||||
self.do_process_groups(groups);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue