/*--------------------------------------------------------- * OpenERP web library *---------------------------------------------------------*/ openerp.web.views = function(db) { var _t = db.web._t; /** * Registry for all the client actions key: tag value: widget */ db.web.client_actions = new db.web.Registry(); /** * Registry for all the main views */ db.web.views = new db.web.Registry(); db.web.ActionManager = db.web.Widget.extend({ identifier_prefix: "actionmanager", init: function(parent) { this._super(parent); this.inner_viewmanager = null; this.dialog = null; this.dialog_viewmanager = null; this.client_widget = null; }, render: function() { return "
"; }, dialog_stop: function () { if (this.dialog) { this.dialog_viewmanager.stop(); this.dialog_viewmanager = null; this.dialog.stop(); this.dialog = null; } }, content_stop: function () { if (this.inner_viewmanager) { this.inner_viewmanager.stop(); this.inner_viewmanager = null; } if (this.client_widget) { this.client_widget.stop(); this.client_widget = null; } }, url_update: function(action) { var url = {}; if(action.id) url.action_id = action.id; // this.url = { // "model": action.res_model, // "domain": action.domain, // }; // action.res_model // action.domain // action.context // after // action.views // action.res_id // mode // menu this.do_url_set_hash(url); }, do_url_set_hash: function(url) { }, on_url_hashchange: function(url) { var self = this; self.rpc("/web/action/load", { action_id: url.action_id }, function(result) { self.do_action(result.result); }); }, do_action: function(action, on_close) { var type = action.type.replace(/\./g,'_'); var popup = action.target === 'new'; action.flags = _.extend({ views_switcher : !popup, search_view : !popup, action_buttons : !popup, sidebar : !popup, pager : !popup }, action.flags || {}); if (!(type in this)) { console.log("Action manager can't handle action of type " + action.type, action); return; } this[type](action, on_close); }, ir_actions_act_window: function (action, on_close) { if (action.target === 'new') { if (this.dialog == null) { this.dialog = new db.web.Dialog(this, { title: action.name, width: '80%' }); if(on_close) this.dialog.on_close.add(on_close); this.dialog.start(); } else { this.dialog_viewmanager.stop(); } this.dialog_viewmanager = new db.web.ViewManagerAction(this, action); this.dialog_viewmanager.appendTo(this.dialog.$element); this.dialog.open(); } else { this.dialog_stop(); this.content_stop(); this.inner_viewmanager = new db.web.ViewManagerAction(this, action); this.inner_viewmanager.appendTo(this.$element); this.url_update(action); } /* new window code this.rpc("/web/session/save_session_action", { the_action : action}, function(key) { var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "?" + jQuery.param({ s_action : "" + key }); window.open(url,'_blank'); }); */ }, ir_actions_act_window_close: function (action, on_closed) { this.dialog_stop(); }, ir_actions_server: function (action, on_closed) { var self = this; this.rpc('/web/action/run', { action_id: action.id, context: action.context || {} }).then(function (action) { self.do_action(action, on_closed) }); }, ir_actions_client: function (action) { this.content_stop(); var ClientWidget = db.web.client_actions.get_object(action.tag); (this.client_widget = new ClientWidget(this, action.params)).appendTo(this); }, ir_actions_report_xml: function(action) { var self = this; $.blockUI(); self.rpc("/web/session/eval_domain_and_context", { contexts: [action.context], domains: [] }).then(function(res) { action = _.clone(action); action.context = res.context; self.session.get_file({ url: '/web/report', data: {action: JSON.stringify(action)}, complete: $.unblockUI }); }); } }); db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{ identifier_prefix: "viewmanager", template: "ViewManager", /** * @constructs db.web.ViewManager * @extends db.web.Widget * * @param parent * @param dataset * @param views */ init: function(parent, dataset, views) { this._super(parent); this.model = dataset.model; this.dataset = dataset; this.searchview = null; this.active_view = null; this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;}); this.views = {}; this.flags = this.flags || {}; this.registry = db.web.views; }, render: function() { return db.web.qweb.render(this.template, { self: this, prefix: this.element_id, views: this.views_src}); }, /** * @returns {jQuery.Deferred} initial view loading promise */ start: function() { this._super(); var self = this; this.dataset.start(); this.$element.find('.oe_vm_switch button').click(function() { self.on_mode_switch($(this).data('view-type')); }); var views_ids = {}; _.each(this.views_src, function(view) { self.views[view.view_type] = $.extend({}, view, { controller : null, options : _.extend({ sidebar_id : self.element_id + '_sidebar_' + view.view_type, action : self.action, action_views_ids : views_ids }, self.flags, view.options || {}) }); views_ids[view.view_type] = view.view_id; }); if (this.flags.views_switcher === false) { this.$element.find('.oe_vm_switch').hide(); } // switch to the first one in sequence return this.on_mode_switch(this.views_src[0].view_type); }, /** * Asks the view manager to switch visualization mode. * * @param {String} view_type type of view to display * @returns {jQuery.Deferred} new view loading promise */ on_mode_switch: function(view_type) { var self = this, view_promise; this.active_view = view_type; var view = this.views[view_type]; if (!view.controller) { // Lazy loading of views var controllerclass = this.registry.get_object(view_type); var controller = new controllerclass(this, this.dataset, view.view_id, view.options); if (view.embedded_view) { controller.set_embedded_view(view.embedded_view); } controller.do_switch_view.add_last(this.on_mode_switch); if (view_type === 'list' && this.flags.search_view === false && this.action && this.action['auto_search']) { // In case the search view is not instantiated: manually call ListView#search var domains = !_(self.action.domain).isEmpty() ? [self.action.domain] : [], contexts = !_(self.action.context).isEmpty() ? [self.action.context] : []; controller.on_loaded.add({ callback: function () { controller.do_search(domains, contexts, []); }, position: 'last', unique: true }); } var container = $("#" + this.element_id + '_view_' + view_type); view_promise = controller.appendTo(container); $.when(view_promise).then(function() { self.on_controller_inited(view_type, controller); }); this.views[view_type].controller = controller; } if (this.searchview) { if (view.controller.searchable === false) { this.searchview.hide(); } else { this.searchview.show(); } } this.$element .find('.views-switchers button').removeAttr('disabled') .filter('[data-view-type="' + view_type + '"]') .attr('disabled', true); for (var view_name in this.views) { if (!this.views.hasOwnProperty(view_name)) { continue; } if (this.views[view_name].controller) { if (view_name === view_type) { $.when(view_promise).then(this.views[view_name].controller.do_show); } else { this.views[view_name].controller.do_hide(); } } } return view_promise; }, /** * Event launched when a controller has been inited. * * @param {String} view_type type of view * @param {String} view the inited controller */ on_controller_inited: function(view_type, view) { }, /** * Sets up the current viewmanager's search view. * * @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; if (this.searchview) { this.searchview.stop(); } this.searchview = new db.web.SearchView( this, this.dataset, view_id, search_defaults); this.searchview.on_search.add(function(domains, contexts, groupbys) { var controller = self.views[self.active_view].controller; controller.do_search.call(controller, domains, contexts, groupbys); }); return this.searchview.appendTo($("#" + this.element_id + "_search")); }, /** * 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 () {} }); db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.ViewManagerAction# */{ template:"ViewManagerAction", /** * @constructs db.web.ViewManagerAction * @extends db.web.ViewManager * * @param {db.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. this.session = parent.session; this.action = action; var dataset = new db.web.DataSetSearch(this, action.res_model, action.context, action.domain); if (action.res_id) { dataset.ids.push(action.res_id); dataset.index = 0; } this._super(parent, dataset, action.views); this.flags = this.action.flags || {}; if (action.res_model == 'board.board' && action.views.length == 1 && action.views) { // Not elegant but allows to avoid form chrome (pager, save/new // buttons, sidebar, ...) displaying this.flags.search_view = this.flags.pager = this.flags.sidebar = this.flags.action_buttons = false; } // setup storage for session-wise menu hiding if (this.session.hidden_menutips) { return; } this.session.hidden_menutips = {} }, /** * 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; var searchview_loaded; if (this.flags.search_view !== false) { var 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); if (searchview_loaded && this.action['auto_search']) { // schedule auto_search manager_ready.then(this.searchview.do_search); } this.$element.find('.oe_get_xml_view').click(function () { // TODO: add search view? $('').text(db.web.json_node_to_xml(
self.views[self.active_view].controller.fields_view.arch, true))
.dialog({ width: '95%'});
});
if (this.action.help && !this.flags.low_profile) {
var Users = new db.web.DataSet(self, 'res.users'),
header = this.$element.find('.oe-view-manager-header');
header.delegate('blockquote button', 'click', function() {
var $this = $(this);
//noinspection FallthroughInSwitchStatementJS
switch ($this.attr('name')) {
case 'disable':
Users.write(self.session.uid, {menu_tips:false});
case 'hide':
$this.closest('blockquote').hide();
self.session.hidden_menutips[self.action.id] = true;
}
});
if (!(self.action.id in self.session.hidden_menutips)) {
Users.read_ids([this.session.uid], ['menu_tips'], function(users) {
var user = users[0];
if (!(user && user.id === self.session.uid)) {
return;
}
header.find('blockquote').toggle(user.menu_tips);
});
}
}
return manager_ready;
},
on_mode_switch: function (view_type) {
var self = this;
return $.when(
this._super(view_type),
this.shortcut_check(this.views[view_type])).then(function () {
var view_id = self.views[self.active_view].controller.fields_view.view_id;
self.$element.find('.oe_get_xml_view span').text(view_id);
});
},
shortcut_check : function(view) {
var self = this;
var grandparent = this.widget_parent && this.widget_parent.widget_parent;
// display shortcuts if on the first view for the action
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
if (!(grandparent instanceof db.web.WebClient) ||
!(view.view_type === this.views_src[0].view_type
&& view.view_id === this.views_src[0].view_id)) {
$shortcut_toggle.hide();
return;
}
$shortcut_toggle.removeClass('oe-shortcut-remove').show();
if (_(this.session.shortcuts).detect(function (shortcut) {
return shortcut.res_id === self.session.active_id; })) {
$shortcut_toggle.addClass("oe-shortcut-remove");
}
this.shortcut_add_remove();
},
shortcut_add_remove: function() {
var self = this;
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
$shortcut_toggle
.unbind("click")
.click(function() {
if ($shortcut_toggle.hasClass("oe-shortcut-remove")) {
$(self.session.shortcuts.binding).trigger('remove-current');
$shortcut_toggle.removeClass("oe-shortcut-remove");
} else {
$(self.session.shortcuts.binding).trigger('add', {
'user_id': self.session.uid,
'res_id': self.session.active_id,
'resource': 'ir.ui.menu',
'name': self.action.name
});
$shortcut_toggle.addClass("oe-shortcut-remove");
}
});
},
/**
* Intercept do_action resolution from children views
*/
on_action_executed: function () {
new db.web.DataSet(this, 'res.log')
.call('get', [], this.do_display_log);
},
/**
* @param {Array