').addClass('active').text(_.last(breadcrumbs).title));
+ this.$breadcrumbs
+ .empty()
+ .append($breadcrumbs);
+ },
+ create_view: function(view) {
+ var self = this,
+ View = this.registry.get_object(view.type),
+ options = _.clone(view.options);
+
+ if (view.type === "form" && this.action && (this.action.target === 'new' || this.action.target === 'inline')) {
options.initial_mode = 'edit';
}
- var controller = new viewclass(this, this.dataset, view.view_id, options);
+ var controller = new View(this, this.dataset, view.view_id, options),
+ $container = this.$(".oe-view-manager-view-" + view.type + ":first");
- controller.on('history_back', this, function() {
- var am = self.getParent();
- if (am && am.trigger) {
- return am.trigger('history_back');
- }
- });
-
- controller.on("change:title", this, function() {
- if (self.active_view === view_type) {
- self.set_title(controller.get('title'));
- }
- });
+ $container.hide();
+ view.controller = controller;
if (view.embedded_view) {
controller.set_embedded_view(view.embedded_view);
}
- controller.on('switch_mode', self, this.switch_mode);
- controller.on('previous_view', self, this.prev_view);
+ controller.on('switch_mode', this, this.switch_mode.bind(this));
- var container = this.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_type);
- var view_promise = controller.appendTo(container);
- this.views[view_type].controller = controller;
- return $.when(view_promise).done(function() {
- self.views[view_type].deferred.resolve(view_type);
- if (self.searchview
- && self.flags.auto_search
- && view.controller.searchable !== false) {
- self.searchview.ready.done(self.searchview.do_search);
- } else {
- self.view_completely_inited.resolve();
- }
- self.trigger("controller_inited",view_type,controller);
+ view.$container = $container;
+
+ var view_loaded = $.Deferred();
+ view.controller.on('view_loaded', this, function () {
+ view_loaded.resolve();
});
+
+ return $.when(controller.appendTo($container), view_loaded)
+ .done(function () {
+ self.trigger("controller_inited", view.type, controller);
+ });
},
- /**
- * @returns {Number|Boolean} the view id of the given type, false if not found
- */
- get_view_id: function(view_type) {
- return this.views[view_type] && this.views[view_type].view_id || false;
- },
- set_title: function(title) {
- this.$el.find('.oe_view_title_text:first').text(title);
- },
- add_breadcrumb: function(options) {
- options = options || {};
- var self = this;
- var views = [this.active_view || this.views_src[0].view_type];
- this.on('switch_mode', self, function(mode) {
- var last = views.slice(-1)[0];
- if (mode !== last) {
- if (mode !== 'form') {
- views.length = 0;
- }
- views.push(mode);
- }
- instance.web.bus.trigger('view_switch_mode', self, mode);
- });
- var item = _.extend({
- widget: this,
- action: this.action,
- show: function(index) {
- var view_to_select = views[index];
- var state = self.url_states[view_to_select];
- self.do_push_state(state || {});
- $.when(self.switch_mode(view_to_select)).done(function() {
- self.$el.show();
- });
- },
- get_title: function() {
- var id;
- var currentIndex;
- _.each(self.getParent().breadcrumbs, function(bc, i) {
- if (bc.widget === self) {
- currentIndex = i;
- }
- });
- var next = self.getParent().breadcrumbs.slice(currentIndex + 1)[0];
- var titles = _.map(views, function(v) {
- var controller = self.views[v].controller;
- if (v === 'form') {
- id = controller.datarecord.id;
- }
- return controller.get('title');
- });
- if (next && next.action && next.action.res_id && self.dataset &&
- self.active_view === 'form' && self.dataset.model === next.action.res_model && id === next.action.res_id) {
- // If the current active view is a formview and the next item in the breadcrumbs
- // is an action on same object (model / res_id), then we omit the current formview's title
- titles.pop();
- }
- return titles;
- }
- }, options);
- this.getParent().push_breadcrumb(item);
- },
- /**
- * Returns to the view preceding the caller view in this manager's
- * navigation history (the navigation history is appended to via
- * switch_mode)
- *
- * @param {Object} [options]
- * @param {Boolean} [options.created=false] resource was created
- * @param {String} [options.default=null] view to switch to if no previous view
- * @returns {$.Deferred} switching end signal
- */
- prev_view: function (options) {
- options = options || {};
- var current_view = this.views_history.pop();
- var previous_view = this.views_history[this.views_history.length - 1] || options['default'];
- if (options.created && current_view === 'form' && previous_view === 'list') {
- // APR special case: "If creation mode from list (and only from a list),
- // after saving, go to page view (don't come back in list)"
- return this.switch_mode('form');
- } else if (options.created && !previous_view && this.action && this.action.flags.default_view === 'form') {
- // APR special case: "If creation from dashboard, we have no previous view
- return this.switch_mode('form');
- }
- return this.switch_mode(previous_view, true);
+ select_view: function (index) {
+ var view_type = this.view_stack[index].type;
+ this.view_stack.splice(index);
+ return this.switch_mode(view_type);
},
/**
* Sets up the current viewmanager's search view.
@@ -826,25 +707,37 @@ instance.web.ViewManager = instance.web.Widget.extend({
* @param {Number|false} view_id the view to use or false for a default one
* @returns {jQuery.Deferred} search view startup deferred
*/
- setup_search_view: function(view_id, search_defaults) {
- var self = this;
+ setup_search_view: function() {
if (this.searchview) {
this.searchview.destroy();
}
+ var view_id = (this.action && this.action.search_view_id && this.action.search_view_id[0]) || false;
+ var search_defaults = {};
+
+ var context = this.action ? this.action.context : [];
+ _.each(context, function (value, key) {
+ var match = /^search_default_(.*)$/.exec(key);
+ if (match) {
+ search_defaults[match[1]] = value;
+ }
+ });
+
+
var options = {
hidden: this.flags.search_view === false,
disable_custom_filters: this.flags.search_disable_custom_filters,
};
- this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, options);
+ var SearchView = instance.web.SearchView;
+ this.searchview = new SearchView(this, this.dataset, view_id, search_defaults, options);
- this.searchview.on('search_data', self, this.do_searchview_search);
- return this.searchview.appendTo(this.$(".oe_view_manager_view_search"),
- this.$(".oe_searchview_drawer_container"));
+ this.searchview.on('search_data', this, this.search.bind(this));
+ return this.searchview.appendTo(this.$(".oe-view-manager-search-view:first"),
+ this.$('.oe_searchview_drawer_container'));
},
- do_searchview_search: function(domains, contexts, groupbys) {
+ search: function(domains, contexts, groupbys) {
var self = this,
- controller = this.views[this.active_view].controller,
+ controller = this.active_view.controller,
action_context = this.action.context || {};
instance.web.pyeval.eval_domains_and_contexts({
domains: [this.action.domain || []].concat(domains || []),
@@ -865,301 +758,48 @@ instance.web.ViewManager = instance.web.Widget.extend({
groupby = [groupby];
}
$.when(controller.do_search(results.domain, results.context, groupby || [])).then(function() {
- self.view_completely_inited.resolve();
+ self.active_search.resolve();
});
});
},
- /**
- * Called when one of the view want to execute an action
- */
- on_action: function(action) {
- },
- on_create: function() {
- },
- on_remove: function() {
- },
- on_edit: function() {
- },
- /**
- * Called by children view after executing an action
- */
- on_action_executed: function () {
- },
-});
-
-instance.web.ViewManagerAction = instance.web.ViewManager.extend({
- template:"ViewManagerAction",
- /**
- * @constructs instance.web.ViewManagerAction
- * @extends instance.web.ViewManager
- *
- * @param {instance.web.ActionManager} parent parent object/widget
- * @param {Object} action descriptor for the action this viewmanager needs to manage its views.
- */
- init: function(parent, action) {
- // dataset initialization will take the session from ``this``, so if we
- // do not have it yet (and we don't, because we've not called our own
- // ``_super()``) rpc requests will blow up.
- var flags = action.flags || {};
- if (!('auto_search' in flags)) {
- flags.auto_search = action.auto_search !== false;
- }
- if (action.res_model == 'board.board' && action.view_mode === 'form') {
- // Special case for Dashboards
- _.extend(flags, {
- views_switcher : false,
- display_title : false,
- search_view : false,
- pager : false,
- sidebar : false,
- action_buttons : false
- });
- }
- this._super(parent, null, action.views, flags);
- this.session = parent.session;
- this.action = action;
- var context = action.context;
- if (action.target === 'current'){
- var active_context = {
- active_model: action.res_model,
- };
- context = new instance.web.CompoundContext(context, active_context).eval();
- delete context['active_id'];
- delete context['active_ids'];
- if (action.res_id){
- context['active_id'] = action.res_id;
- context['active_ids'] = [action.res_id];
- }
- }
- var dataset = new instance.web.DataSetSearch(this, action.res_model, context, action.domain);
- if (action.res_id) {
- dataset.ids.push(action.res_id);
- dataset.index = 0;
- }
- this.dataset = dataset;
- },
- /**
- * Initializes the ViewManagerAction: sets up the searchview (if the
- * searchview is enabled in the manager's action flags), calls into the
- * parent to initialize the primary view and (if the VMA has a searchview)
- * launches an initial search after both views are done rendering.
- */
- start: function() {
- var self = this,
- searchview_loaded,
- search_defaults = {};
- _.each(this.action.context, function (value, key) {
- var match = /^search_default_(.*)$/.exec(key);
- if (match) {
- search_defaults[match[1]] = value;
- }
- });
- // init search view
- var searchview_id = this.action['search_view_id'] && this.action['search_view_id'][0];
-
- searchview_loaded = this.setup_search_view(searchview_id || false, search_defaults);
-
- var main_view_loaded = this._super();
-
- var manager_ready = $.when(searchview_loaded, main_view_loaded, this.view_completely_inited);
-
- this.$el.find('.oe_debug_view').change(this.on_debug_changed);
- this.$el.addClass("oe_view_manager_" + (this.action.target || 'current'));
- return manager_ready;
- },
- on_debug_changed: function (evt) {
- var self = this,
- $sel = $(evt.currentTarget),
- $option = $sel.find('option:selected'),
- val = $sel.val(),
- current_view = this.views[this.active_view].controller;
- switch (val) {
- case 'fvg':
- var dialog = new instance.web.Dialog(this, { title: _t("Fields View Get") }).open();
- $('').text(instance.web.json_node_to_xml(current_view.fields_view.arch, true)).appendTo(dialog.$el);
- break;
- case 'tests':
- this.do_action({
- name: _t("JS Tests"),
- target: 'new',
- type : 'ir.actions.act_url',
- url: '/web/tests?mod=*'
- });
- break;
- case 'get_metadata':
- var ids = current_view.get_selected_ids();
- if (ids.length === 1) {
- this.dataset.call('get_metadata', [ids]).done(function(result) {
- var dialog = new instance.web.Dialog(this, {
- title: _.str.sprintf(_t("Metadata (%s)"), self.dataset.model),
- size: 'medium',
- }, QWeb.render('ViewManagerDebugViewLog', {
- perm : result[0],
- format : instance.web.format_value
- })).open();
- });
- }
- break;
- case 'toggle_layout_outline':
- current_view.rendering_engine.toggle_layout_debugging();
- break;
- case 'set_defaults':
- current_view.open_defaults_dialog();
- break;
- case 'translate':
- this.do_action({
- name: _t("Technical Translation"),
- res_model : 'ir.translation',
- domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']],
- views: [[false, 'list'], [false, 'form']],
- type : 'ir.actions.act_window',
- view_type : "list",
- view_mode : "list"
- });
- break;
- case 'fields':
- this.dataset.call('fields_get', [false, {}]).done(function (fields) {
- var $root = $('');
- _(fields).each(function (attributes, name) {
- $root.append($('- ').append($('
').text(name)));
- var $attrs = $('').appendTo($('- ').appendTo($root));
- _(attributes).each(function (def, name) {
- if (def instanceof Object) {
- def = JSON.stringify(def);
- }
- $attrs
- .append($('
- ').text(name))
- .append($('
- ').text(def));
- });
- });
- new instance.web.Dialog(self, {
- title: _.str.sprintf(_t("Model %s fields"),
- self.dataset.model),
- }, $root).open();
- });
- break;
- case 'edit_workflow':
- return this.do_action({
- res_model : 'workflow',
- domain : [['osv', '=', this.dataset.model]],
- views: [[false, 'list'], [false, 'form'], [false, 'diagram']],
- type : 'ir.actions.act_window',
- view_type : 'list',
- view_mode : 'list'
- });
- case 'edit':
- this.do_edit_resource($option.data('model'), $option.data('id'), { name : $option.text() });
- break;
- case 'manage_filters':
- this.do_action({
- res_model: 'ir.filters',
- views: [[false, 'list'], [false, 'form']],
- type: 'ir.actions.act_window',
- context: {
- search_default_my_filters: true,
- search_default_model_id: this.dataset.model
- }
- });
- break;
- case 'print_workflow':
- if (current_view.get_selected_ids && current_view.get_selected_ids().length == 1) {
- instance.web.blockUI();
- var action = {
- context: { active_ids: current_view.get_selected_ids() },
- report_name: "workflow.instance.graph",
- datas: {
- model: this.dataset.model,
- id: current_view.get_selected_ids()[0],
- nested: true,
- }
- };
- this.session.get_file({
- url: '/web/report',
- data: {action: JSON.stringify(action)},
- complete: instance.web.unblockUI
- });
- }
- break;
- default:
- if (val) {
- console.log("No debug handler for ", val);
- }
- }
- evt.currentTarget.selectedIndex = 0;
- },
- do_edit_resource: function(model, id, action) {
- action = _.extend({
- res_model : model,
- res_id : id,
- type : 'ir.actions.act_window',
- view_type : 'form',
- view_mode : 'form',
- views : [[false, 'form']],
- target : 'new',
- flags : {
- action_buttons : true,
- form : {
- resize_textareas : true
- }
- }
- }, action || {});
- this.do_action(action);
- },
- switch_mode: function (view_type, no_store, options) {
- var self = this;
-
- return this.alive($.when(this._super.apply(this, arguments))).done(function () {
- var controller = self.views[self.active_view].controller;
- self.$el.find('.oe_debug_view').html(QWeb.render('ViewManagerDebug', {
- view: controller,
- view_manager: self
- }));
- self.set_title();
- });
- },
- do_create_view: function(view_type) {
- var self = this;
- return this._super.apply(this, arguments).then(function() {
- var view = self.views[view_type].controller;
- view.set({ 'title': self.action.name });
- });
- },
- get_action_manager: function() {
- var cur = this;
- while ((cur = cur.getParent())) {
- if (cur instanceof instance.web.ActionManager) {
- return cur;
- }
- }
- return undefined;
- },
- set_title: function(title) {
- this.$el.find('.oe_breadcrumb_title:first').html(this.get_action_manager().get_title());
- },
do_push_state: function(state) {
- if (this.getParent() && this.getParent().do_push_state) {
- state["view_type"] = this.active_view;
- this.url_states[this.active_view] = state;
- this.getParent().do_push_state(state);
+ if (this.action_manager) {
+ state.view_type = this.active_view.type;
+ this.action_manager.do_push_state(state);
}
- },
+ },
do_load_state: function(state, warm) {
var self = this,
defs = [];
- if (state.view_type && state.view_type !== this.active_view) {
+ if (state.view_type && state.view_type !== this.active_view.type) {
defs.push(
- this.views[this.active_view].deferred.then(function() {
+ this.active_view.created.then(function() {
return self.switch_mode(state.view_type, true);
})
);
}
- $.when(this.views[this.active_view] ? this.views[this.active_view].deferred : $.when(), defs).done(function() {
- self.views[self.active_view].controller.do_load_state(state, warm);
+ $.when(this.active_view ? this.active_view.created : null, defs).done(function() {
+ self.active_view.controller.do_load_state(state, warm);
});
},
});
+instance.web.ViewManagerAction = instance.web.ViewManager.extend({
+ template:"ViewManagerAction",
+
+ init: function (parent, action) {
+ var flags = action.flags || {};
+ if (!('auto_search' in flags)) {
+ flags.auto_search = action.auto_search !== false;
+ }
+ this.action = action;
+ this.action_manager = parent;
+ var dataset = new instance.web.DataSetSearch(this, action.res_model, action.context, action.domain);
+ this._super(parent, dataset, action.views, flags);
+ }
+});
+
instance.web.Sidebar = instance.web.Widget.extend({
init: function(parent) {
var self = this;
@@ -1331,7 +971,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
a.url = prefix + '&id=' + a.id + '&t=' + (new Date().getTime());
}
});
- self.items['files'] = attachments;
+ self.items.files = attachments;
self.redraw();
this.$('.oe_sidebar_add_attachment .oe_form_binary_file').change(this.on_attachment_changed);
this.$el.find('.oe_sidebar_delete_item').click(this.on_attachment_delete);
@@ -1519,9 +1159,7 @@ instance.web.View = instance.web.Widget.extend({
this.$el.hide();
},
is_active: function () {
- var manager = this.getParent();
- return !manager || !manager.active_view
- || manager.views[manager.active_view].controller === this;
+ return this.ViewManager.active_view.controller === this;
}, /**
* Wraps fn to only call it if the current view is the active one. If the
* current view is not active, doesn't call fn.
@@ -1544,7 +1182,8 @@ instance.web.View = instance.web.Widget.extend({
this.getParent().do_push_state(state);
}
},
- do_load_state: function(state, warm) {
+ do_load_state: function (state, warm) {
+
},
/**
* Switches to a specific view type
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index f99a96b649b..656b1c9c080 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -476,57 +476,45 @@
-
-
-
-
-
-
-
-
-
-
-
+
@@ -745,7 +733,7 @@