this.mutating_mutex = new $.Mutex();
this.on_change_list = [];
this.save_list = [];
+ this.render_value_defs = [];
this.reload_mutex = new $.Mutex();
this.__clicked_inside = false;
this.__blur_timeout = null;
this.$el.off('.formBlur');
}
this._super();
+ if (this.$buttons) {
+ this.$buttons.remove();
+ }
},
load_form: function(data) {
var self = this;
});
}
return $.when();
+ }).fail(function() {
+ self.save_list.pop();
+ return $.when();
});
};
return iterate();
} else if (mode === "create") {
mode = "edit";
}
+ this.render_value_defs = [];
this.set({actual_mode: mode});
},
check_actual_mode: function(source, options) {
}
}
},
- on_button_save: function() {
+ on_button_save: function(e) {
var self = this;
+ $(e.target).attr("disabled", true);
return this.save().done(function(result) {
self.trigger("save", result);
self.reload().then(function() {
parent.menu.do_reload_needaction();
}
});
+ }).always(function(){
+ $(e.target).attr("disabled", false);
});
},
on_button_cancel: function(event) {
+ var self = this;
if (this.can_be_discarded()) {
if (this.get('actual_mode') === 'create') {
this.trigger('history_back');
} else {
this.to_view_mode();
- this.trigger('load_record', this.datarecord);
+ $.when.apply(null, this.render_value_defs).then(function(){
+ self.trigger('load_record', self.datarecord);
+ });
}
}
this.trigger('on_button_cancel');
context: {
'bin_size': true,
'future_display_name': true
- }
+ },
+ check_access_rule: true
}).then(function(r) {
self.trigger('load_record', r);
+ }).fail(function (){
+ self.do_action('history_back');
});
}
});
return this.view.do_execute_action(
_.extend({}, this.node.attrs, {context: context}),
- this.view.dataset, this.view.datarecord.id, function () {
- self.view.recursive_reload();
+ this.view.dataset, this.view.datarecord.id, function (reason) {
+ if (!_.isObject(reason)) {
+ self.view.recursive_reload();
+ }
});
},
check_disable: function() {
instance.web.form.ReinitializeFieldMixin = _.extend({}, instance.web.form.ReinitializeWidgetMixin, {
reinitialize: function() {
instance.web.form.ReinitializeWidgetMixin.reinitialize.call(this);
- this.render_value();
+ var res = this.render_value();
+ if (this.view && this.view.render_value_defs){
+ this.view.render_value_defs.push(res);
+ }
},
});
type_of_date: "datetime",
events: {
'change .oe_datepicker_master': 'change_datetime',
+ 'keypress .oe_datepicker_master': 'change_datetime',
},
init: function(parent) {
this._super(parent);
format_client: function(v) {
return instance.web.format_value(v, {"widget": this.type_of_date});
},
- change_datetime: function() {
- if (this.is_valid_()) {
+ change_datetime: function(e) {
+ if ((e.type !== "keypress" || e.which === 13) && this.is_valid_()) {
this.set_value_from_ui_();
this.trigger("datetime_changed");
}
},
set_dimensions: function (height, width) {
this._super(height, width);
- this.datewidget.$input.css('height', height);
+ if (!this.get("effective_readonly")) {
+ this.datewidget.$input.css('height', height);
+ }
}
});
e.stopPropagation();
}
},
+ 'keypress': function (e) {
+ if (e.which === $.ui.keyCode.ENTER) {
+ e.stopPropagation();
+ }
+ },
'change textarea': 'store_dom_value',
},
initialize_content: function() {
if (! this.get("effective_readonly")) {
self._updating_editor = false;
this.$textarea = this.$el.find('textarea');
- var width = ((this.node.attrs || {}).editor_width || '100%');
+ var width = ((this.node.attrs || {}).editor_width || 'calc(100% - 4px)');
var height = ((this.node.attrs || {}).editor_height || 250);
this.$textarea.cleditor({
width: width, // width not including margins, borders or padding
if (self.options.quick_create === undefined || self.options.quick_create) {
new instance.web.DataSet(this, this.field.relation, self.build_context())
.name_create(name).done(function(data) {
- self.add_id(data[0]);
+ if (!self.get('effective_readonly'))
+ self.add_id(data[0]);
}).fail(function(error, event) {
event.preventDefault();
slow_create();
this.floating = false;
this.current_display = null;
this.is_started = false;
+ this.ignore_focusout = false;
},
reinit_value: function(val) {
this.internal_set_value(val);
self.display_value = {};
self.render_value();
self.focus();
- self.view.do_onchange(self);
+ self.trigger('changed_value');
});
});
var ed_delay = 200;
var ed_duration = 15000;
var anyoneLoosesFocus = function (e) {
+ if (self.ignore_focusout) { return; }
var used = false;
if (self.floating) {
if (self.last_search.length > 0) {
// disabled to solve a bug, but may cause others
//close: anyoneLoosesFocus,
minLength: 0,
- delay: 0
+ delay: 250
});
this.$input.autocomplete("widget").openerpClass();
// used to correct a bug when selecting an element by pushing 'enter' in an editable list
if (! no_recurse) {
var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.build_context());
this.alive(dataset.name_get([self.get("value")])).done(function(data) {
+ if (!data[0]) {
+ self.do_warn(_t("Render"), _t("No value found for the field "+self.field.string+" for value "+self.get("value")));
+ return;
+ }
self.display_value["" + self.get("value")] = data[0][1];
self.render_value(true);
});
_search_create_popup: function() {
this.no_ed = true;
this.ed_def.reject();
- return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments);
+ this.ignore_focusout = true;
+ this.reinit_value(false);
+ var res = instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments);
+ this.ignore_focusout = false;
+ this.no_ed = false;
+ return res;
},
set_dimensions: function (height, width) {
this._super(height, width);
- this.$input.css('height', height);
+ if (!this.get("effective_readonly") && this.$input)
+ this.$input.css('height', height);
}
});
};
instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
multi_selection: false,
- disable_utility_classes: true,
init: function(field_manager, node) {
this._super(field_manager, node);
lazy_build_o2m_kanban_view();
}
return $.when(false);
},
+ is_false: function() {
+ return this.dataset.ids.length == 0;
+ },
is_syntax_valid: function() {
if (! this.viewmanager || ! this.viewmanager.views[this.viewmanager.active_view])
return true;
instance.web.form.One2ManyDataSet = instance.web.BufferedDataSet.extend({
get_context: function() {
this.context = this.o2m.build_context();
+ var self = this;
+ _.each(arguments, function(context) {
+ self.context.add(context);
+ });
return this.context;
}
});
GroupsType: instance.web.form.One2ManyGroups,
ListType: instance.web.form.One2ManyList
}));
- this.on('edit:before', this, this.proxy('_before_edit'));
this.on('edit:after', this, this.proxy('_after_edit'));
this.on('save:before cancel:before', this, this.proxy('_before_unedit'));
var ret = this._super();
this.$el
.off('mousedown.handleButtons')
- .on('mousedown.handleButtons', 'table button', this.proxy('_button_down'));
+ .on('mousedown.handleButtons', 'table button, div a.oe_m2o_cm_button', this.proxy('_button_down'));
return ret;
},
changed_records: function () {
this.o2m.trigger_on_change();
},
is_valid: function () {
- var editor = this.editor;
- var form = editor.form;
- // If no edition is pending, the listview can not be invalid (?)
- if (!editor.record) {
- return true
- }
- // If the form has not been modified, the view can only be valid
- // NB: is_dirty will also be set on defaults/onchanges/whatever?
- // oe_form_dirty seems to only be set on actual user actions
- if (!form.$el.is('.oe_form_dirty')) {
+ var self = this;
+ if (!this.fields_view || !this.editable()){
return true;
}
- this.o2m._dirty_flag = true;
-
- // Otherwise validate internal form
- return _(form.fields).chain()
- .invoke(function () {
- this._check_css_flags();
- return this.is_valid();
- })
- .all(_.identity)
- .value();
+ var r;
+ return _.every(this.records.records, function(record){
+ r = record;
+ _.each(self.editor.form.fields, function(field){
+ field._inhibit_on_change_flag = true;
+ field.set_value(r.attributes[field.name]);
+ field._inhibit_on_change_flag = false;
+ });
+ return _.every(self.editor.form.fields, function(field){
+ field.process_modifiers();
+ field._check_css_flags();
+ return field.is_valid();
+ });
+ });
},
do_add_record: function () {
if (this.editable()) {
else
return $.when();
}).done(function () {
- if (!self.o2m.options.reload_on_button) {
+ var ds = self.o2m.dataset;
+ var cached_records = _.any([ds.to_create, ds.to_delete, ds.to_write], function(value) {
+ return value.length;
+ });
+ if (!self.o2m.options.reload_on_button && !cached_records) {
self.handle_button(name, id, callback);
}else {
self.handle_button(name, id, function(){
});
},
- _before_edit: function () {
+ _after_edit: function () {
this.__ignore_blur = false;
this.editor.form.on('blurred', this, this._on_form_blur);
- },
- _after_edit: function () {
+
// The form's blur thing may be jiggered during the edition setup,
// potentially leading to the o2m instasaving the row. Cancel any
// blurring triggered the edition startup here
} finally {
window.confirm = confirm;
}
+ },
+ reload_record: function (record) {
+ // Evict record.id from cache to ensure it will be reloaded correctly
+ this.dataset.evict_record(record.get('id'));
+
+ return this._super(record);
}
});
instance.web.form.One2ManyGroups = instance.web.ListView.Groups.extend({
}
};
if (! values || values.length > 0) {
- this._display_orderer.add(dataset.name_get(values)).done(handle_names);
+ return this._display_orderer.add(dataset.name_get(values)).done(handle_names);
} else {
handle_names([]);
}
*/
instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
multi_selection: false,
- disable_utility_classes: true,
init: function(field_manager, node) {
this._super(field_manager, node);
this.is_loaded = $.Deferred();
pop.select_element(
this.model,
{
- title: _t("Add: ") + this.m2m_field.string
+ title: _t("Add: ") + this.m2m_field.string,
+ no_create: this.m2m_field.options.no_create,
},
new instance.web.CompoundDomain(this.m2m_field.build_domain(), ["!", ["id", "in", this.m2m_field.dataset.ids]]),
this.m2m_field.build_context()
this.searchview.on('search_data', self, function(domains, contexts, groupbys) {
if (self.initial_ids) {
self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]),
- contexts, groupbys);
+ contexts.concat(self.context), groupbys);
self.initial_ids = undefined;
} else {
self.do_search(domains.concat([self.domain]), contexts.concat(self.context), groupbys);
.on('blurred', null, function () {self.trigger('blurred')});
this.m2o = new instance.web.form.FieldMany2One(fm, { attrs: {
- name: 'm2o',
+ name: 'Referenced Document',
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
}});
this.m2o.on("change:value", this, this.data_changed);
this._super.apply(this, arguments);
this.render_value();
this.set_filename('');
+ },
+ set_value: function(value_){
+ var changed = value_ !== this.get_value();
+ this._super.apply(this, arguments);
+ // By default, on binary images read, the server returns the binary size
+ // This is possible that two images have the exact same size
+ // Therefore we trigger the change in case the image value hasn't changed
+ // So the image is re-rendered correctly
+ if (!changed){
+ this.trigger("change:value", this, {
+ oldValue: value_,
+ newValue: value_
+ });
+ }
}
});
* Options on attribute ; "blockui" {Boolean} block the UI or not
* during the file is uploading
*/
-instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({
+instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: "FieldBinaryFileUploader",
init: function(field_manager, node) {
this._super(field_manager, node);
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
$(window).on(this.fileupload_id, _.bind(this.on_file_loaded, this));
},
- start: function() {
- this._super(this);
+ initialize_content: function() {
this.$el.on('change', 'input.oe_form_binary_file', this.on_file_change );
},
set_value: function(value_) {
if (this.options.clickable) {
this.$el.on('click','li',this.on_click_stage);
}
- if (this.$el.parent().is('header')) {
- this.$el.after('<div class="oe_clear"/>');
- }
this._super();
},
set_value: function(value_) {
on_click_stage: function (ev) {
var self = this;
var $li = $(ev.currentTarget);
- var val = parseInt($li.data("id"));
+ if (this.field.type == "many2one") {
+ var val = parseInt($li.data("id"));
+ }
+ else {
+ var val = $li.data("id");
+ }
if (val != self.get('value')) {
this.view.recursive_save().done(function() {
var change = {};