diff --git a/src/board.js b/src/board.js index 02ee3414bb..7207c7993b 100644 --- a/src/board.js +++ b/src/board.js @@ -21,7 +21,7 @@ if (attributes.yfill === undefined) { attributes.yfill = true; } - action = new Sao.View.Board.Action(attributes, this.view.context); + action = new Sao.View.Board.Action(this.view, attributes); this.view.actions.push(action); this.container.add(action, attributes); }, @@ -55,17 +55,22 @@ for (i = 0; i < this.state_widgets.length; i++) { this.state_widgets[i].set_state(null); } - } + }, + active_changed: function(event_action) { + this.actions.forEach(function(action) { + if (action === event_action) { + return; + } + action.update_domain(this.actions); + }); + }, }); Sao.View.Board.Action = Sao.class_(Object, { - init: function(attributes, context) { - if (context === undefined) { - context = {}; - } - + init: function(view, attributes) { var session = Sao.Session.current_session; this.name = attributes.name; + this.view = view; this.el = jQuery('
', { 'class': 'board-action panel panel-default', @@ -105,7 +110,7 @@ ctx._user = session.user_id; var decoder = new Sao.PYSON.Decoder(ctx); params.context = jQuery.extend( - {}, context, + {}, this.view.context, decoder.decode(action.pyson_context || '{}')); ctx = jQuery.extend(ctx, params.context); @@ -181,6 +186,9 @@ display: function() { this.screen.search_filter(this.screen.screen_container.get_text()); }, + record_message: function() { + this.view.active_changed(this); + }, get_active: function() { if (this.screen && this.screen.current_record) { return Sao.common.EvalEnvironment(this.screen.current_record); diff --git a/src/common.js b/src/common.js index 5c9b6034da..95223ad296 100644 --- a/src/common.js +++ b/src/common.js @@ -919,7 +919,7 @@ (this.attributes.type === 'class')) && (record)) { var parent = record.group.parent; while (parent) { - if (parent.has_changed()) { + if (parent.modified) { this.el.prop('disabled', true); break; } diff --git a/src/model.js b/src/model.js index ed7636c903..e99bba144c 100644 --- a/src/model.js +++ b/src/model.js @@ -116,13 +116,9 @@ this.record_deleted = record_deleted; if (new_records.length && modified) { new_records.forEach(function(record) { - record._changed.id = true; - }); - var root_group = this.root_group; - this.changed(); - root_group.screens.forEach(function(screen) { - screen.display(); + record.modified_fields.id = true; }); + this.record_modified(); } }; array.get = function(id) { @@ -168,9 +164,8 @@ this.record_deleted.indexOf(record_del), 1); } } - record._changed.id = true; + record.set_modified('id'); if (changed) { - this.changed(); // Set parent field to trigger on_change if (this.parent && this.model.fields[this.parent_name]) { var field = this.model.fields[this.parent_name]; @@ -214,16 +209,16 @@ } } if (record.group.parent) { - record.group.parent._changed.id = true; + record.group.parent.set_modified('id'); } if (modified) { - record._changed.id = true; + record.set_modified('id'); } if ((record.id < 0) || force_remove) { this._remove(record); } if (signal) { - record.group.changed(); + this.record_modified(); } }; array._remove = function(record) { @@ -233,27 +228,24 @@ array.unremove = function(record) { this.record_removed.splice(this.record_removed.indexOf(record), 1); this.record_deleted.splice(this.record_deleted.indexOf(record), 1); - record.group.changed(); + record.group.record_modified(); }; array.clear = function() { this.splice(0, this.length); this.record_removed = []; this.record_deleted = []; }; - array.changed = function() { + array.record_modified = function() { if (!this.parent) { - return jQuery.when.apply(jQuery, - this.screens.map(function(screen) { - if (screen.group_changed_callback) { - screen.group_changed_callback(); - } - return screen.display(); - })); + this.screens.forEach(function(screen) { + screen.record_modified(); + }); + } else { + this.parent.modified_fields[this.child_name] = true; + this.parent.model.fields[this.child_name].changed(this.parent); + this.parent.validate(null, true, false, true); + this.parent.group.record_modified(); } - this.parent._changed[this.child_name] = true; - this.parent.model.fields[this.child_name].changed(this.parent); - this.parent.validate(null, true, false, true); - this.parent.group.changed(); }; array.delete_ = function(records) { if (jQuery.isEmptyObject(records)) { @@ -332,7 +324,7 @@ }); ids.forEach(function(id) { var record = this.get(id); - if (record && jQuery.isEmptyObject(record._changed)) { + if (record && !record.modified_fields) { record.cancel(); } }.bind(this)); @@ -376,9 +368,7 @@ new_.forEach(function(record) { record.set_default(values, true, false); }); - this.root_group.screens.forEach(function(screen) { - return screen.display(); - }); + this.changed(); }.bind(this)); } }; @@ -568,7 +558,7 @@ Sao.Record.prototype.id_counter--; } this._values = {}; - this._changed = {}; + this.modified_fields = {}; this._loaded = {}; this.fields = {}; this._timestamp = null; @@ -582,11 +572,11 @@ this.exception = false; this.destroyed = false; }, - has_changed: function() { - if (!jQuery.isEmptyObject(this._changed)) { + get modified() { + if (!jQuery.isEmptyObject(this.modified_fields)) { Sao.Logger.info( "Modified fields of %s@%s", this.id, this.model.name, - Object.keys(this._changed)); + Object.keys(this.modified_fields)); return true; } else { return false; @@ -598,7 +588,7 @@ } var context = this.get_context(); var prm = jQuery.when(); - if ((this.id < 0) || this.has_changed()) { + if ((this.id < 0) || this.modified) { var values = this.get(); if (this.id < 0) { // synchronous call to avoid multiple creation @@ -634,7 +624,7 @@ } } if (this.group.parent) { - delete this.group.parent._changed[this.group.child_name]; + delete this.group.parent.modified_fields[this.group.child_name]; prm = prm.done(function() { return this.group.parent.save(force_reload); }.bind(this)); @@ -816,8 +806,8 @@ } var value = id2value[id]; if (record && value) { - for (var key in this._changed) { - if (!this._changed.hasOwnProperty(key)) { + for (var key in this.modified_fields) { + if (!this.modified_fields.hasOwnProperty(key)) { continue; } delete value[key]; @@ -919,7 +909,7 @@ !(field instanceof Sao.field.Many2Many))) { continue; } - if ((this._changed[name] === undefined) && this.id >= 0) { + if ((this.modified_fields[name] === undefined) && this.id >= 0) { continue; } value[name] = field.get(this); @@ -1069,7 +1059,7 @@ continue; } if ((this.id >= 0) && - (!this._loaded[key] || !this._changed[key])) { + (!this._loaded[key] || !this.modified_fields[key])) { continue; } value[key] = this.model.fields[key].get_on_change_value(this); @@ -1302,11 +1292,11 @@ } }, pre_validate: function() { - if (jQuery.isEmptyObject(this._changed)) { + if (jQuery.isEmptyObject(this.modified_fields)) { return jQuery.Deferred().resolve(true); } var values = this._get_on_change_args( - Object.keys(this._changed).concat(['id'])); + Object.keys(this.modified_fields).concat(['id'])); return this.model.execute('pre_validate', [values], this.get_context()) .then(function() { @@ -1317,7 +1307,7 @@ }, cancel: function() { this._loaded = {}; - this._changed = {}; + this.modified_fields = {}; this._timestamp = null; this.button_clicks = {}; this.links_counts = {}; @@ -1332,7 +1322,7 @@ if (!jQuery.isEmptyObject(fields)) { var result = true; fields.forEach(function(field) { - if (!(field in this._loaded) && !(field in this._changed)) { + if (!(field in this._loaded) && !(field in this.modified_fields)) { result = false; } }.bind(this)); @@ -1483,6 +1473,12 @@ return clicks; }.bind(this)); }, + set_modified: function(field) { + if (field) { + this.modified_fields[field] = true; + } + this.group.record_modified(); + }, destroy: function() { var vals = Object.values(this._values); for (var i=0; i < vals.length; i++) { @@ -1568,18 +1564,13 @@ var previous_value = this.get(record); this.set(record, value); if (this._has_changed(previous_value, this.get(record))) { - record._changed[this.name] = true; this.changed(record); record.validate(null, true, false, true); - record.group.changed(); + record.set_modified(this.name); } else if (force_change) { - record._changed[this.name] = true; this.changed(record); record.validate(null, true, false, true); - var root_group = record.group.root_group; - root_group.screens.forEach(function(screen) { - screen.display(); - }); + this.set_modified(); } }, get_client: function(record) { @@ -1587,11 +1578,11 @@ }, set_default: function(record, value) { this.set(record, value); - record._changed[this.name] = true; + record.modified_fields[this.name] = true; }, set_on_change: function(record, value) { this.set(record, value); - record._changed[this.name] = true; + record.modified_fields[this.name] = true; }, changed: function(record) { record.on_change([this.name]); @@ -2276,7 +2267,7 @@ } var values; if (record2.id >= 0) { - if (record2.has_changed()) { + if (record2.modified) { values = record2.get(); delete values[parent_name]; if (!jQuery.isEmptyObject(values)) { @@ -2327,18 +2318,13 @@ previous_ids.sort(), value.sort()); this._set_value(record, value, false, modified); if (modified) { - record._changed[this.name] = true; this.changed(record); record.validate(null, true, false, true); - record.group.changed(); + record.set_modified(this.name); } else if (force_change) { - record._changed[this.name] = true; this.changed(record); record.validate(null, true, false, true); - var root_group = record.group.root_group; - root_group.screens.forEach(function(screen) { - screen.display(); - }); + record.set_modified(); } }, get_client: function(record) { @@ -2346,12 +2332,12 @@ return record._values[this.name]; }, set_default: function(record, value) { - record._changed[this.name] = true; + record.modified_fields[this.name] = true; return this.set(record, value, true); }, set_on_change: function(record, value) { var fields, new_fields; - record._changed[this.name] = true; + record.modified_fields[this.name] = true; this._set_default_value(record); if (value instanceof Array) { return this._set_value(record, value, false, true); @@ -2487,7 +2473,7 @@ var timestamps = {}; var group = record._values[this.name] || []; var records = group.filter(function(record) { - return record.has_changed(); + return record.modified; }); var record2; jQuery.extend(records, group.record_removed, group.record_deleted) diff --git a/src/screen.js b/src/screen.js index 9b979d4bfe..15c75b96e7 100644 --- a/src/screen.js +++ b/src/screen.js @@ -798,6 +798,7 @@ Sao.Screen = Sao.class_(Object, { init: function(model_name, attributes) { this.model_name = model_name; + this.windows = []; this.model = new Sao.Model(model_name, attributes); this.attributes = jQuery.extend({}, attributes); this.view_ids = jQuery.extend([], attributes.view_ids); @@ -862,10 +863,7 @@ this.fields_view_tree = {}; this._domain_parser = {}; this.pre_validate = false; - this.tab = null; - this.message_callback = null; this.switch_callback = null; - this.group_changed_callback = null; // count_tab_domain is called in Sao.Tab.Form.init after // switch_view to avoid unnecessary call to fields_view_get by // domain_parser. @@ -1252,38 +1250,71 @@ group.readonly = this.attributes.readonly; this.set_group(group); }, + record_modified: function(display) { + this.windows.forEach(function(window_) { + if (window_.record_modified) { + window_.record_modified(); + } + }); + if (display || display === undefined) { + return this.display(); + } + }, + record_message: function(position, size, max_size, record_id) { + this.windows.forEach(function(window_) { + if (window_.record_message) { + window_.record_message(position, size, max_size, record_id); + } + }); + }, + record_saved: function() { + this.windows.forEach(function(window_) { + if (window_.record_saved) { + window_.record_saved(); + } + }); + }, + update_resources: function(resources) { + this.windows.forEach(function(window_) { + if (window_.update_resources) { + window_.update_resources(resources); + } + }); + }, + has_update_resources: function() { + return this.windows.some(function(window_) { + return window_.update_resources; + }); + }, get current_record() { return this.__current_record; }, set current_record(record) { this.__current_record = record; - if (this.message_callback){ - var pos = null; - var record_id = null; - if (record) { - var i = this.group.indexOf(record); - if (i >= 0) { - pos = i + this.offset + 1; - } else { - pos = record.get_index_path(); - } - record_id = record.id; + var pos = null; + var record_id = null; + if (record) { + var i = this.group.indexOf(record); + if (i >= 0) { + pos = i + this.offset + 1; + } else { + pos = record.get_index_path(); } - var data = [pos || 0, this.group.length + this.offset, - this.search_count, record_id]; - this.message_callback(data); + record_id = record.id; } + this.record_message( + pos || 0, this.group.length + this.offset, this.search_count, + record_id); if (this.switch_callback) { this.switch_callback(); } - if (this.tab) { + if (this.has_update_resources()) { if (record) { record.get_resources().always( - this.tab.update_resources.bind(this.tab)); + this.update_resources.bind(this)); } else { - this.tab.update_resources(); + this.update_resources(); } - this.tab.record_message(); } }, load: function(ids, set_cursor, modified) { @@ -1595,7 +1626,7 @@ }, modified: function() { var test = function(record) { - return (record.has_changed() || record.id < 0); + return (record.modified || record.id < 0); }; if (this.current_view.view_type != 'tree') { if (this.current_record) { diff --git a/src/tab.js b/src/tab.js index 69e333f972..aa36706aad 100644 --- a/src/tab.js +++ b/src/tab.js @@ -472,14 +472,13 @@ this.set_name(name); attributes.breadcrumb = [name]; var screen = new Sao.Screen(model_name, attributes); - screen.tab = this; + screen.windows.push(this); this.screen = screen; this.info_bar = new Sao.Window.InfoBar(); this.create_tabcontent(); this.attachment_screen = null; - screen.message_callback = this.record_message.bind(this); screen.switch_callback = function() { if (this === Sao.Tab.tabs.get_current()) { Sao.set_url(this.get_url(), this.name.split(' / ').pop()); @@ -807,8 +806,8 @@ return this.modified_save().then(function() { return this.screen.new_().then(function() { this.info_bar.message(); + this.activate_save(); }.bind(this)); - // TODO activate_save }.bind(this)); }, save: function(tab) { @@ -866,7 +865,7 @@ .then(function(set_cursor) { return this.screen.display(set_cursor).then(function() { this.info_bar.message(); - // TODO activate_save + this.activate_save(); this.screen.count_tab_domain(); }.bind(this)); }.bind(this)); @@ -920,7 +919,7 @@ return this.modified_save().then(function() { var prm = this.screen.display_previous(); this.info_bar.message(); - // TODO activate_save + this.activate_save(); return prm; }.bind(this)); }, @@ -928,7 +927,7 @@ return this.modified_save().then(function() { var prm = this.screen.display_next(); this.info_bar.message(); - // TODO activate_save + this.activate_save(); return prm; }.bind(this)); }, @@ -1063,7 +1062,7 @@ var name = e[0]; var access = e[1]; if (this.buttons[name]) { - this.buttons[name].toggleClass('disabled', !access); + this.buttons[name].prop('disabled', !access); } if (this.menu_buttons[name]) { this.menu_buttons[name] @@ -1074,7 +1073,7 @@ ['new_', 'save', 'delete_', 'copy', 'import'].forEach( function(name) { if (this.buttons[name]) { - this.buttons[name].addClass('disabled'); + this.buttons[name].prop('disabled', true); } if (this.menu_buttons[name]) { this.menu_buttons[name].addClass('disabled'); @@ -1304,14 +1303,14 @@ screen.display_next(); }); - screen.message_callback = function(data) { - var position = data[0]; - var length = data[1]; + preview = {}; + preview.record_message = function(position, length) { var text = (position || '_') + '/' + length; label.text(text).attr('title', text); but_prev.prop('disabled', !position || position <= 1); but_next.prop('disabled', !position || position >= length); }; + screen.windows.push(preview); screen.switch_view().done(function() { el.append(screen.screen_container.el); @@ -1350,7 +1349,7 @@ function is_report(action) { return action.type == 'ir.action.report'; } - if (!this.buttons.email.hasClass('disabled')) { + if (!this.buttons.email.prop('disabled')) { this.modified_save().then(function() { var record = this.screen.current_record; if (!record || (record.id < 0)) { @@ -1448,52 +1447,63 @@ title = Sao.i18n.gettext("Note (%1/%2)", unread, count); update('note', title, badge, color); }, - record_message: function(data) { - if (data) { - var name = "_"; - if (data[0] !== 0) { - name = data[0]; - } - var buttons = ['print', 'relate', 'email', 'save', 'attach']; - buttons.forEach(function(button_id){ - var button = this.buttons[button_id]; - var can_be_sensitive = button._can_be_sensitive; - if (can_be_sensitive === undefined) { - can_be_sensitive = true; - } - if ((button_id == 'print') || - (button_id == 'relate') || - (button_id == 'email')) { - can_be_sensitive |= this.screen.get_buttons().some( - function(button) { - var keyword = button.attributes.keyword || 'action'; - return keyword == button_id; - }); - } else if (button_id == 'save') { - can_be_sensitive &= !this.screen.readonly; - } - button.prop('disabled', !(data[0] && can_be_sensitive)); - }.bind(this)); - this.buttons.switch_.prop('disabled', - this.attributes.view_ids > 1); - - this.menu_buttons.delete_.toggleClass( - 'disabled', !this.screen.deletable); - this.menu_buttons.save.toggleClass( - 'disabled', this.screen.readonly); - - var msg = name + ' / ' + data[1]; - if ((data[1] < data[2]) && - this.screen.limit !== null && - (data[2] > this.screen.limit)) { - msg += Sao.i18n.gettext(' of ') + data[2]; - } - this.status_label.text(msg).attr('title', msg); + record_message: function(position, size, max_size, record_id) { + var name = "_"; + if (position) { + name = position; } + var buttons = ['print', 'relate', 'email', 'save', 'attach']; + buttons.forEach(function(button_id){ + var button = this.buttons[button_id]; + var can_be_sensitive = button._can_be_sensitive; + if (can_be_sensitive === undefined) { + can_be_sensitive = true; + } + if ((button_id == 'print') || + (button_id == 'relate') || + (button_id == 'email')) { + can_be_sensitive |= this.screen.get_buttons().some( + function(button) { + var keyword = button.attributes.keyword || 'action'; + return keyword == button_id; + }); + } else if (button_id == 'save') { + can_be_sensitive &= !this.screen.readonly; + } + button.prop('disabled', !(position && can_be_sensitive)); + }.bind(this)); + this.buttons.switch_.prop('disabled', + this.attributes.view_ids > 1); + + this.menu_buttons.delete_.toggleClass( + 'disabled', !this.screen.deletable); + this.menu_buttons.save.toggleClass( + 'disabled', this.screen.readonly); + this.buttons.save.prop('disabled', this.screen.readonly); + + var msg = name + ' / ' + size; + if ((size < max_size) && + this.screen.limit !== null && + (max_size > this.screen.limit)) { + msg += Sao.i18n.gettext(' of ') + max_size; + } + this.status_label.text(msg).attr('title', msg); this.info_bar.message(); - // TODO activate_save + this.activate_save(); this.refresh_attachment_preview(); }, + record_modified: function() { + this.activate_save(); + }, + record_saved: function() { + this.activate_save(); + this.refresh_resources(); + }, + activate_save: function() { + this.menu_buttons.save.toggleClass( + 'disabled', !this.screen.modified()); + this.buttons.save.prop('disabled', !this.screen.modified()); + }, action: function() { window.setTimeout(function() { this.buttons.action.click(); @@ -1604,7 +1614,7 @@ var i, len, action; for (i = 0, len = this.board.actions.length; i < len; i++) { action = this.board.actions[i]; - action.screen.tab = this; + action.screen.windows.push(this); } this.board.reload(); }.bind(this)); diff --git a/src/view/form.js b/src/view/form.js index b1aa89da39..b8773f8025 100644 --- a/src/view/form.js +++ b/src/view/form.js @@ -1262,6 +1262,8 @@ function eval_pyson(value){ } this.set_value(); }, + get_value: function() { + }, set_value: function() { }, set_readonly: function(readonly) { @@ -1272,6 +1274,16 @@ function eval_pyson(value){ get modified() { return false; }, + send_modified: function() { + window.setTimeout(function() { + var value = this.get_value(); + window.setTimeout(function() { + if (this.record && (this.get_value() == value)) { + this.view.screen.record_modified(false); + } + }.bind(this), 300); + }.bind(this)); + }, set_invisible: function(invisible) { this.visible = !invisible; if (invisible) { @@ -1442,7 +1454,7 @@ function eval_pyson(value){ } }; Sao.View.Form.TranslateMixin.translate = function() { - if (this.record.id < 0 || this.record.has_changed()) { + if (this.record.id < 0 || this.record.modified) { var mg = Sao.i18n.gettext( 'You need to save the record before adding translations.'); Sao.common.message.run(mg); @@ -1514,6 +1526,7 @@ function eval_pyson(value){ this.input.attr('autocomplete', 'off'); } this.el.change(this.focus_out.bind(this)); + this.el.on('keydown', this.send_modified.bind(this)); if (!attributes.size) { this.group.css('width', '100%'); @@ -1662,6 +1675,7 @@ function eval_pyson(value){ 'name': attributes.name, }).appendTo(group); this.date.uniqueId(); + this.date.on('keydown', this.send_modified.bind(this)); this.input = jQuery('', { 'type': this._input, 'role': 'button', @@ -1680,6 +1694,7 @@ function eval_pyson(value){ this.date.val(value).change(); this.date.focus(); } + this.send_modified(); }.bind(this)); if (this.input[0].type == this._input) { this.icon = jQuery('
', { @@ -1839,6 +1854,7 @@ function eval_pyson(value){ 'name': attributes.name, }).appendTo(this.el); this.el.change(this.focus_out.bind(this)); + this.el.on('keydown', this.send_modified.bind(this)); }, display: function() { Sao.View.Form.TimeDelta._super.display.call(this); @@ -2205,6 +2221,7 @@ function eval_pyson(value){ 'name': attributes.name, }).appendTo(this.el); this.input.change(this.focus_out.bind(this)); + this.input.on('keydown', this.send_modified.bind(this)); if (this.attributes.translate) { var button = jQuery('