diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6f72d836ea4..72868647a48 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1417,6 +1417,7 @@ class ExcelExport(Export): for cell_index, cell_value in enumerate(row): if isinstance(cell_value, basestring): cell_value = re.sub("\r", " ", cell_value) + if cell_value is False: cell_value = None worksheet.write(row_index + 1, cell_index, cell_value, style) fp = StringIO() diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 1929c573e42..0b49e1cc52d 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -887,8 +887,11 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W */ render_element: function() { var rendered = this.render(); - if (rendered || rendered === "") - this.$element = $(rendered); + if (rendered) { + var elem = $(rendered); + this.$element.replaceWith(elem); + this.$element = elem; + } return this; }, /** @@ -900,7 +903,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W render: function (additional) { if (this.template) return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); - return false; + return null; }, /** * Method called after rendering. Mostly used to bind actions, perform asynchronous @@ -912,12 +915,6 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * @returns {jQuery.Deferred} */ start: function() { - /* The default implementation is only useful for retro-compatibility, it is - not necessary to call it using _super() when using Widget for new components. */ - if (!this.$element) { - var tmp = document.getElementById(this.element_id); - this.$element = tmp ? $(tmp) : undefined; - } return $.Deferred().done().promise(); }, /** diff --git a/addons/web/static/src/js/dates.js b/addons/web/static/src/js/dates.js index 036cf8cd90b..7861dd21b79 100644 --- a/addons/web/static/src/js/dates.js +++ b/addons/web/static/src/js/dates.js @@ -18,11 +18,11 @@ openerp.web.str_to_datetime = function(str) { var regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/; var res = regex.exec(str); if ( !res ) { - throw "'" + str + "' is not a valid datetime"; + throw new Error("'" + str + "' is not a valid datetime"); } var obj = Date.parse(res[1] + " GMT"); if (! obj) { - throw "'" + str + "' is not a valid datetime"; + throw new Error("'" + str + "' is not a valid datetime"); } return obj; }; @@ -41,11 +41,11 @@ openerp.web.str_to_date = function(str) { var regex = /^\d\d\d\d-\d\d-\d\d$/; var res = regex.exec(str); if ( !res ) { - throw "'" + str + "' is not a valid date"; + throw new Error("'" + str + "' is not a valid date"); } var obj = Date.parse(str); if (! obj) { - throw "'" + str + "' is not a valid date"; + throw new Error("'" + str + "' is not a valid date"); } return obj; }; @@ -64,11 +64,11 @@ openerp.web.str_to_time = function(str) { var regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/; var res = regex.exec(str); if ( !res ) { - throw "'" + str + "' is not a valid time"; + throw new Error("'" + str + "' is not a valid time"); } var obj = Date.parse(res[1]); if (! obj) { - throw "'" + str + "' is not a valid time"; + throw new Error("'" + str + "' is not a valid time"); } return obj; }; diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index ca540844b7f..d5fcdd35b62 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -93,7 +93,7 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) { } while(tmp !== value); tmp = Number(value); if (isNaN(tmp)) - throw value + " is not a correct integer"; + throw new Error(value + " is not a correct integer"); return tmp; case 'float': var tmp = Number(value); @@ -107,42 +107,42 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) { } while(tmp !== tmp2); tmp = Number(tmp); if (isNaN(tmp)) - throw value + " is not a correct float"; + throw new Error(value + " is not a correct float"); return tmp; case 'float_time': - var tmp = value.split(":"); - if (tmp.length != 2) - throw value + " is not a correct float_time"; - var tmp1 = openerp.web.parse_value(tmp[0], {type: "integer"}); - var tmp2 = openerp.web.parse_value(tmp[1], {type: "integer"}); - return tmp1 + (tmp2 / 60); + var float_time_pair = value.split(":"); + if (float_time_pair.length != 2) + return openerp.web.parse_value(value, {type: "float"}); + var hours = openerp.web.parse_value(float_time_pair[0], {type: "integer"}); + var minutes = openerp.web.parse_value(float_time_pair[1], {type: "integer"}); + return hours + (minutes / 60); case 'progressbar': return openerp.web.parse_value(value, {type: "float"}); case 'datetime': - var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, - Date.CultureInfo.formatPatterns.longTime)); - if (tmp !== null) - return openerp.web.datetime_to_str(tmp); - tmp = Date.parse(value); - if (tmp !== null) - return openerp.web.datetime_to_str(tmp); - throw value + " is not a valid datetime"; + var datetime = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, + Date.CultureInfo.formatPatterns.longTime)); + if (datetime !== null) + return openerp.web.datetime_to_str(datetime); + datetime = Date.parse(value); + if (datetime !== null) + return openerp.web.datetime_to_str(datetime); + throw new Error(value + " is not a valid datetime"); case 'date': - var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate); - if (tmp !== null) - return openerp.web.date_to_str(tmp); - tmp = Date.parse(value); - if (tmp !== null) - return openerp.web.date_to_str(tmp); - throw value + " is not a valid date"; + var date = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate); + if (date !== null) + return openerp.web.date_to_str(date); + date = Date.parse(value); + if (date !== null) + return openerp.web.date_to_str(date); + throw new Error(value + " is not a valid date"); case 'time': - var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime); - if (tmp !== null) - return openerp.web.time_to_str(tmp); - tmp = Date.parse(value); - if (tmp !== null) - return openerp.web.time_to_str(tmp); - throw value + " is not a valid time"; + var time = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime); + if (time !== null) + return openerp.web.time_to_str(time); + time = Date.parse(value); + if (time !== null) + return openerp.web.time_to_str(time); + throw new Error(value + " is not a valid time"); } return value; }; @@ -157,7 +157,7 @@ openerp.web.auto_str_to_date = function(value, type) { try { return openerp.web.str_to_time(value); } catch(e) {} - throw "'" + value + "' is not a valid date, datetime nor time" + throw new Error("'" + value + "' is not a valid date, datetime nor time"); }; openerp.web.auto_date_to_str = function(value, type) { @@ -169,7 +169,7 @@ openerp.web.auto_date_to_str = function(value, type) { case 'time': return openerp.web.time_to_str(value); default: - throw type + " is not convertible to date, datetime nor time" + throw new Error(type + " is not convertible to date, datetime nor time"); } }; diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 18e035a40b8..0ceab43f1fd 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -963,10 +963,7 @@ openerp.web.search.ExtendedSearch = openerp.web.OldWidget.extend({ this.check_last_element(); }, start: function () { - this._super(); - if (!this.$element) { - return; // not a logical state but sometimes it happens - } + this.$element = $("#" + this.element_id); this.$element.closest("table.oe-searchview-render-line").css("display", "none"); var self = this; this.rpc("/web/searchview/fields_get", @@ -1028,7 +1025,7 @@ openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({ prop.start(); }, start: function () { - this._super(); + this.$element = $("#" + this.element_id); var _this = this; this.add_prop(); this.$element.find('.searchview_extended_add_proposition').click(function () { @@ -1080,7 +1077,7 @@ openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** this.value = null; }, start: function () { - this._super(); + this.$element = $("#" + this.element_id); this.select_field(this.fields.length > 0 ? this.fields[0] : null); var _this = this; this.$element.find(".searchview_extended_prop_field").change(function() { @@ -1188,7 +1185,7 @@ openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.OldWidget.ex return this.datewidget.get_value(); }, start: function() { - this._super(); + this.$element = $("#" + this.element_id); this.datewidget = new openerp.web.DateTimeWidget(this); this.datewidget.prependTo(this.$element); } @@ -1208,7 +1205,7 @@ openerp.web.search.ExtendedSearchProposition.Date = openerp.web.OldWidget.extend return this.datewidget.get_value(); }, start: function() { - this._super(); + this.$element = $("#" + this.element_id); this.datewidget = new openerp.web.DateWidget(this); this.datewidget.prependTo(this.$element); } diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index 2008a5d2129..376eed6fe71 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -32,7 +32,8 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ action_buttons: false, search_view: false, pager: false, - radio: true + radio: true, + select_view_id: self.parent.fields_view.view_id }, }; this.view_edit_dialog = new openerp.web.Dialog(this, { @@ -53,6 +54,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ } }, }).start().open(); + this.main_view_id = this.parent.fields_view.view_id; var action_manager = new openerp.web.ActionManager(this); action_manager.appendTo(this.view_edit_dialog); $.when(action_manager.do_action(action)).then(function() { @@ -572,7 +574,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ var value = _.detect(arch_val[0]['att_list'],function(res) { return _.include(res, id); }); - if (id == 'groups') type_widget.value = self.groups; + if (id == 'groups') type_widget.selection = self.groups; self.edit_node_dialog.$element.find('table[id=rec_table]').append(''+id+':'+type_widget.render()+''); type_widget.start(); type_widget.set_value(value); @@ -630,9 +632,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ "Update": function(){ var update_values = []; _.each(self.edit_widget, function(widget) { - if (widget.dirty) { - update_values.push(widget.get_value()); - } + update_values.push(widget.get_value()); }); }, "Cancel": function(){ @@ -645,7 +645,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ var table_selector = self.add_node_dialog.$element.find('table[id=rec_table]'); _.each(render_list,function(node){ type_widget = new openerp.web.ViewEditor.FieldSelect (self.add_node_dialog, node[0]); - type_widget.value = node[1]; + type_widget.selection = node[1]; if(node[0]=="Fields"){ node[0] = "";} table_selector.append(''+node[0]+''+type_widget.render()+''); type_widget.start(); @@ -664,7 +664,6 @@ openerp.web.ViewEditor.Field = openerp.web.Class.extend({ this.$element = view.$element; this.dirty = false; this.name = id; - this.value = undefined; }, on_ui_change: function() { this.dirty = true; @@ -714,17 +713,18 @@ openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({ this.$element.find("select[id=" + this.name + "]").css('width', '100%').change(function() { self.on_ui_change(); add_node = self.get_value(); - if(add_node[0] == "node_type" && add_node[1] == "field" ){ - self.$element.find("select[id=Fields]").show(); - }else{self.$element.find("select[id=Fields]").hide();} + if(add_node[0] == "node_type"){ + if(add_node[1] == "field"){self.$element.find("select[id=Fields]").show();} + else{self.$element.find("select[id=Fields]").hide();} + } }); }, set_value: function(value) { value = value === null ? false : value; value = value instanceof Array ? value[1] : value; var index = 0; - for (var i = 0, ii = this.value.length; i < ii; i++) { - if ((this.value[i] instanceof Array && this.value[i][1] === value) || this.value[i] === value) index = i; + for (var i = 0, ii = this.selection.length; i < ii; i++) { + if ((this.selection[i] instanceof Array && this.selection[i][1] === value) || this.selection[i] === value) index = i; } this.$element.find("select[id=" + this.name + "]")[0].selectedIndex = index; }, @@ -740,43 +740,43 @@ openerp.web.ViewEditor.WidgetProperty = openerp.web.ViewEditor.FieldSelect.exten var values = _.keys(this.registry.map); values.push(''); values.sort(); - this.value = values; + this.selection = values; }, }); openerp.web.ViewEditor.IconProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = icons; + this.selection = icons; }, }); openerp.web.ViewEditor.ButtonTargetProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = [['', ''], ['new', 'New Window']]; + this.selection = [['', ''], ['new', 'New Window']]; }, }); openerp.web.ViewEditor.ButtonTypeProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]; + this.selection = [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]; }, }); openerp.web.ViewEditor.AlignProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]; + this.selection = [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]; }, }); openerp.web.ViewEditor.ButtonSpecialProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]; + this.selection = [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]; }, }); openerp.web.ViewEditor.PositionProperty = openerp.web.ViewEditor.FieldSelect.extend({ init: function(view, id) { this._super(view, id); - this.value = [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]; + this.selection = [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]; }, }); openerp.web.ViewEditor.GroupsProperty = openerp.web.ViewEditor.FieldSelect.extend({ @@ -792,7 +792,7 @@ openerp.web.ViewEditor.GroupsProperty = openerp.web.ViewEditor.FieldSelect.exten var self = this; self.$element.find("#groups option").attr("selected",false); if (!value) return false; - _.each(this.value, function(item) { + _.each(this.selection, function(item) { if (_.include(value[1].split(','), item[0])) { self.$element.find("select[id="+self.name+"] option[value='" + item[0] +"']").attr("selected",1) } diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 15790d3c1c0..53d7eeb60fb 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -387,10 +387,16 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# var def = $.Deferred(); $.when(this.has_been_loaded).then(function() { if (self.can_be_discarded() && self.datarecord.id) { - self.dataset.unlink([self.datarecord.id]).then(function() { - self.on_pager_action('next'); - def.resolve(); - }); + if (confirm(_t("Do you really want to delete this record?"))) { + self.dataset.unlink([self.datarecord.id]).then(function() { + self.on_pager_action('next'); + def.resolve(); + }); + } else { + setTimeout(function () { + def.reject(); + }, 0) + } } }); return def.promise(); @@ -2035,7 +2041,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ once.resolve(); }); controller.on_pager_action.add_first(function() { - self.save_form_view(); + self.save_any_view(); }); controller.$element.find(".oe_form_button_save").hide(); } else if (view_type == "graph") { @@ -2044,7 +2050,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ def.resolve(); }); this.viewmanager.on_mode_switch.add_first(function(n_mode, b, c, d, e) { - $.when(self.save_form_view()).then(function() { + $.when(self.save_any_view()).then(function() { if(n_mode === "list") setTimeout(function() {self.reload_current_view();}, 0); }); @@ -2154,7 +2160,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ this.dataset.to_delete, function(x) { return commands['delete'](x.id);})); }, - save_form_view: function() { + save_any_view: function() { if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view && this.viewmanager.views[this.viewmanager.active_view] && this.viewmanager.views[this.viewmanager.active_view].controller) { @@ -2166,6 +2172,13 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ console.warn("Asynchronous get_value() is not supported in form view."); }*/ return res; + } else if (this.viewmanager.active_view === "list") { + var res = $.when(view.ensure_saved()); + // it seems line there are some cases when this happens + /*if (!res.isResolved() && !res.isRejected()) { + console.warn("Asynchronous get_value() is not supported in list view."); + }*/ + return res; } } return false; @@ -2190,7 +2203,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ } }, is_dirty: function() { - this.save_form_view(); + this.save_any_view(); return this._super(); }, update_dom: function() { @@ -2318,6 +2331,10 @@ openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({ 'deletable': self.is_readonly() ? false : true, 'selectable': self.multi_selection }); + var embedded = (this.field.views || {}).tree; + if (embedded) { + this.list_view.set_embedded_view(embedded); + } this.list_view.m2m_field = this; var loaded = $.Deferred(); this.list_view.on_loaded.add_last(function() { @@ -2419,7 +2436,8 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope }, read_function: null}); this.initial_ids = this.options.initial_ids; this.created_elements = []; - openerp.web.form.dialog(this.render(), {close:function() { + this.render_element(); + openerp.web.form.dialog(this.$element, {close:function() { self.check_exit(); }}); this.start(); @@ -2607,7 +2625,8 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp this.row_id = row_id; this.context = context || {}; this.options = _.defaults(options || {}, {"auto_write": true}); - jQuery(this.render()).dialog({title: '', + this.render_element(); + this.$element.dialog({title: '', modal: true, width: 960, height: 600}); @@ -3013,7 +3032,7 @@ openerp.web.form.FieldSelectionReadonly = openerp.web.form.FieldReadonly.extend( this.$element.find('div').text(option ? option[1] : this.values[0][1]); } }); -openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldCharReadonly.extend({ +openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldURIReadonly.extend({ set_value: function (value) { value = value || null; this.invalid = false; @@ -3023,24 +3042,39 @@ openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldCharReadonly.exte self.on_value_changed(); var real_set_value = function(rval) { self.value = rval; - var div = $(self.$element.find('div')); - div.html(''); - var a = $(div.find("a")); - a.text(rval ? rval[1] : ''); - a.click(function() { - var pop = new openerp.web.form.FormOpenPopup(self.view); - pop.show_element(self.field.relation, self.value[0],self.build_context(), {readonly:true}); - }); + self.$element.find('a') + .unbind('click') + .text(rval ? rval[1] : '') + .click(function () { + self.do_action({ + type: 'ir.actions.act_window', + res_model: self.field.relation, + res_id: self.value[0], + context: self.build_context(), + views: [[false, 'form']], + target: 'current' + }); + return false; + }); }; if (value && !(value instanceof Array)) { - var dataset = new openerp.web.DataSetStatic( - this, this.field.relation, self.build_context()); - dataset.name_get([value], function(data) { - real_set_value(data[0]); - }).fail(function() {self.tmp_value = undefined;}); + new openerp.web.DataSetStatic( + this, this.field.relation, self.build_context()) + .name_get([value], function(data) { + real_set_value(data[0]); + }); } else { setTimeout(function() {real_set_value(value);}, 0); } + }, + get_value: function() { + if (!this.value) { + return false; + } else if (this.value instanceof Array) { + return this.value[0]; + } else { + return this.value; + } } }); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index e891a6c7db7..207d12a64e1 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -476,7 +476,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# * @param {Array} ids the ids of the records to delete */ do_delete: function (ids) { - if (!(ids.length && confirm(_t("Are you sure to remove those records ?")))) { + if (!(ids.length && confirm(_t("Do you really want to remove these records?")))) { return; } var self = this; @@ -1145,9 +1145,12 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L row_data[group.grouped_on] = group; var group_column = _(self.columns).detect(function (column) { return column.id === group.grouped_on; }); - $group_column.html(openerp.web.format_cell( - row_data, group_column, _t("Undefined") - )); + try { + $group_column.html(openerp.web.format_cell( + row_data, group_column, _t("Undefined"))); + } catch (e) { + $group_column.html(row_data[group_column.id].value); + } if (group.openable) { // Make openable if not terminal group & group_by_no_leaf $group_column diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index a6aaf02d5e6..92ad85232c4 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -471,7 +471,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner $search_prefix = $title.find('span'); if (controller.searchable !== false) { if (!$search_prefix.length) { - $title.prepend('' + _t("Search:") + ''); + $title.prepend('' + _t("Search: ") + ''); } } else { $search_prefix.remove(); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index f5448168f5e..d8eb6a3f8f4 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -623,18 +623,9 @@ - - - - - - - - - - - - + + + - - - - + \ No newline at end of file