merge lp:openerp-web

bzr revid: jam@tinyerp.com-20120817044830-kex9wpcxvcntj6y0
This commit is contained in:
Jigar Amin - OpenERP 2012-08-17 10:18:30 +05:30
commit 6ace7578fa
15 changed files with 332 additions and 157 deletions

View File

@ -811,9 +811,8 @@ class Session(openerpweb.Controller):
@openerpweb.jsonrequest @openerpweb.jsonrequest
def modules(self, req): def modules(self, req):
loaded = module_boot(req) # return all installed modules. Web client is smart enough to not load a module twice
modules = module_installed(req) return module_installed(req)
return [module for module in modules if module not in loaded]
@openerpweb.jsonrequest @openerpweb.jsonrequest
def eval_domain_and_context(self, req, contexts, domains, def eval_domain_and_context(self, req, contexts, domains,
@ -1142,6 +1141,15 @@ class DataSet(openerpweb.Controller):
def exec_workflow(self, req, model, id, signal): def exec_workflow(self, req, model, id, signal):
return req.session.exec_workflow(model, id, signal) return req.session.exec_workflow(model, id, signal)
@openerpweb.jsonrequest
def resequence(self, req, model, ids):
m = req.session.model(model)
if not len(m.fields_get(['sequence'])):
return False
for i in range(len(ids)):
m.write([ids[i]], { 'sequence': i })
return True
class DataGroup(openerpweb.Controller): class DataGroup(openerpweb.Controller):
_cp_path = "/web/group" _cp_path = "/web/group"
@openerpweb.jsonrequest @openerpweb.jsonrequest

View File

@ -1926,9 +1926,9 @@
margin: 8px; margin: 8px;
} }
.openerp .oe_form_nosheet > header { .openerp .oe_form_nosheet > header {
margin-top: -20px; margin-top: -8px;
margin-left: -20px; margin-left: -8px;
margin-right: -20px; margin-right: -8px;
} }
.openerp .oe_form header { .openerp .oe_form header {
position: relative; position: relative;

View File

@ -1487,9 +1487,9 @@ $sheet-max-width: 860px
.oe_form_nosheet .oe_form_nosheet
margin: 8px margin: 8px
.oe_form_nosheet > header .oe_form_nosheet > header
margin-top: -20px margin-top: -8px
margin-left: -20px margin-left: -8px
margin-right: -20px margin-right: -8px
// }}} // }}}
// FormView.custom tags and classes {{{ // FormView.custom tags and classes {{{
.oe_form .oe_form

View File

@ -621,11 +621,11 @@ instance.web.Reload = instance.web.Widget.extend({
}, },
start: function() { start: function() {
var l = window.location; var l = window.location;
var timestamp = new Date().getTime();
var search = "?ts=" + timestamp; var sobj = $.deparam(l.search.substr(1));
if (l.search) { sobj.ts = new Date().getTime();
search = l.search + "&ts=" + timestamp; var search = '?' + $.param(sobj);
}
var hash = l.hash; var hash = l.hash;
if (this.menu_id) { if (this.menu_id) {
hash = "#menu_id=" + this.menu_id; hash = "#menu_id=" + this.menu_id;
@ -948,7 +948,7 @@ instance.web.Client = instance.web.Widget.extend({
instance.web.bus.on('click', this, function(ev) { instance.web.bus.on('click', this, function(ev) {
$.fn.tipsy.clear(); $.fn.tipsy.clear();
if (!$(ev.target).is('input[type=file]')) { if (!$(ev.target).is('input[type=file]')) {
self.$element.find('.oe_dropdown_menu.oe_opened').removeClass('oe_opened'); self.$element.find('.oe_dropdown_menu.oe_opened, .oe_dropdown_toggle.oe_opened').removeClass('oe_opened');
} }
}); });
}, },

View File

@ -523,14 +523,14 @@ $.async_when = function() {
/** Setup blockui */ /** Setup blockui */
if ($.blockUI) { if ($.blockUI) {
$.blockUI.defaults.baseZ = 1100; $.blockUI.defaults.baseZ = 1100;
$.blockUI.defaults.message = '<div class="oe_blockui_spin" style="height: 50px">'; $.blockUI.defaults.message = '<div class="oe_blockui_spin_container">';
$.blockUI.defaults.css.border = '0'; $.blockUI.defaults.css.border = '0';
$.blockUI.defaults.css["background-color"] = ''; $.blockUI.defaults.css["background-color"] = '';
$.blockUI.spinners = [];
} }
instance.web.blockUI = function() {
var tmp = $.blockUI.apply($, arguments); instance.web.Throbber = instance.web.Widget.extend({
var target = $(".oe_blockui_spin")[0]; template: "Throbber",
start: function() {
var opts = { var opts = {
lines: 13, // The number of lines to draw lines: 13, // The number of lines to draw
length: 7, // The length of each line length: 7, // The length of each line
@ -547,13 +547,26 @@ instance.web.blockUI = function() {
top: 'auto', // Top position relative to parent in px top: 'auto', // Top position relative to parent in px
left: 'auto' // Left position relative to parent in px left: 'auto' // Left position relative to parent in px
}; };
var spinner = new Spinner(opts).spin(target); this.spin = new Spinner(opts).spin(this.$element[0]);
$.blockUI.spinners.push(spinner); },
destroy: function() {
if (this.spin)
this.spin.stop();
this._super();
},
});
instance.web.Throbber.throbbers = [];
instance.web.blockUI = function() {
var tmp = $.blockUI.apply($, arguments);
var throbber = new instance.web.Throbber();
instance.web.Throbber.throbbers.push(throbber);
throbber.appendTo($(".oe_blockui_spin_container"));
return tmp; return tmp;
} }
instance.web.unblockUI = function() { instance.web.unblockUI = function() {
_.each($.blockUI.spinners, function(el) { _.each(instance.web.Throbber.throbbers, function(el) {
el.stop(); el.destroy();
}); });
return $.unblockUI.apply($, arguments); return $.unblockUI.apply($, arguments);
} }

View File

@ -706,7 +706,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend( /** @lends openerp.
* @returns {$.Deferred} * @returns {$.Deferred}
*/ */
call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) { call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) {
return this.rpc('/web/dataset/call', { return instance.session.rpc('/web/dataset/call', {
model: this.model, model: this.model,
method: method, method: method,
domain_id: domain_index == undefined ? null : domain_index, domain_id: domain_index == undefined ? null : domain_index,
@ -805,6 +805,22 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend( /** @lends openerp.
alter_ids: function(n_ids) { alter_ids: function(n_ids) {
this.ids = n_ids; this.ids = n_ids;
}, },
/**
* Resequence records.
*
* @param {Array} ids identifiers of the records to resequence
* @returns {$.Deferred}
*/
resequence: function (ids, options) {
options = options || {};
return instance.session.rpc('/web/dataset/resequence', {
model: this.model,
ids: ids,
context: this._model.context(options.context),
}).pipe(function (results) {
return results;
});
},
}); });
instance.web.DataSetStatic = instance.web.DataSet.extend({ instance.web.DataSetStatic = instance.web.DataSet.extend({
init: function(parent, model, context, ids) { init: function(parent, model, context, ids) {

View File

@ -263,7 +263,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
/** /**
* *
* @param {Object} [options] * @param {Object} [options]
* @param {Boolean} [editable=false] whether the form should be switched to edition mode. A value of ``false`` will keep the current mode. * @param {Boolean} [mode=undefined] If specified, switch the form to specified mode. Can be "edit" or "view".
* @param {Boolean} [reload=true] whether the form should reload its content on show, or use the currently loaded record * @param {Boolean} [reload=true] whether the form should reload its content on show, or use the currently loaded record
* @return {$.Deferred} * @return {$.Deferred}
*/ */
@ -300,9 +300,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
}); });
} }
return shown.pipe(function() { return shown.pipe(function() {
if (options.editable) { self._actualize_mode(options.mode || self.options.initial_mode);
self.to_edit_mode();
}
self.$element.css({ self.$element.css({
opacity: '1', opacity: '1',
filter: 'alpha(opacity = 100)' filter: 'alpha(opacity = 100)'
@ -642,12 +640,21 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this._actualize_mode("edit"); this._actualize_mode("edit");
}, },
/** /**
* Reactualize actual_mode. * Ask the view to switch to a precise mode if possible. The view is free to
* not respect this command if the state of the dataset is not compatible with
* the new mode. For example, it is not possible to switch to edit mode if
* the current record is not yet saved in database.
*
* @param {string} [new_mode] Can be "edit", "view", "create" or undefined. If
* undefined the view will test the actual mode to check if it is still consistent
* with the dataset state.
*/ */
_actualize_mode: function(switch_to) { _actualize_mode: function(switch_to) {
var mode = switch_to || this.get("actual_mode"); var mode = switch_to || this.get("actual_mode");
if (! this.datarecord.id) { if (! this.datarecord.id) {
mode = "create"; mode = "create";
} else if (mode === "create") {
mode = "edit";
} }
this.set({actual_mode: mode}); this.set({actual_mode: mode});
}, },
@ -2724,6 +2731,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
this.floating = false; this.floating = false;
this.render_value(); this.render_value();
}); });
instance.web.bus.on('click', this, function() {
if (!this.get("effective_readonly") && this.$input && this.$input.autocomplete('widget').is(':visible')) {
this.$input.autocomplete("close");
}
});
}, },
initialize_content: function() { initialize_content: function() {
if (!this.get("effective_readonly")) if (!this.get("effective_readonly"))
@ -2975,10 +2987,12 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
}, },
_quick_create: function() { _quick_create: function() {
this.no_tipsy = true; this.no_tipsy = true;
this.tip_def.reject();
return instance.web.form.CompletionFieldMixin._quick_create.apply(this, arguments); return instance.web.form.CompletionFieldMixin._quick_create.apply(this, arguments);
}, },
_search_create_popup: function() { _search_create_popup: function() {
this.no_tipsy = true; this.no_tipsy = true;
this.tip_def.reject();
return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments); return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments);
}, },
}); });

View File

@ -159,8 +159,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
//state = _.extend(this.inner_action.params || {}, state); //state = _.extend(this.inner_action.params || {}, state);
} }
} }
if(!this.dialog) {
this.getParent().do_push_state(state); this.getParent().do_push_state(state);
} }
}
}, },
do_load_state: function(state, warm) { do_load_state: function(state, warm) {
var self = this, var self = this,

View File

@ -1742,5 +1742,12 @@
<div t-name="Many2ManyKanban.quick_create" class="oe_kanban_quick_create"> <div t-name="Many2ManyKanban.quick_create" class="oe_kanban_quick_create">
<input t-att-placeholder="_t('Type name to search')"/> <input t-att-placeholder="_t('Type name to search')"/>
</div> </div>
<t t-name="Throbber">
<div>
<div class="oe_blockui_spin" style="height: 50px">
</div>
<br />
<div style="color:white">Loading...</div>
</div>
</t>
</templates> </templates>

View File

@ -28,7 +28,6 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
width: '80%', width: '80%',
min_width: 850 min_width: 850
}, this.options.action_views_ids.form, dataset); }, this.options.action_views_ids.form, dataset);
this.form_dialog.start();
this.COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', this.COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00', '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
@ -312,29 +311,31 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
}); });
}, },
do_create_event_with_formdialog: function(event_id, event_obj) { do_create_event_with_formdialog: function(event_id, event_obj) {
var self = this;
$.when(! self.form_dialog.dialog_inited ? self.form_dialog.init_dialog() : true).then(function() {
debugger;
if (!event_obj) { if (!event_obj) {
event_obj = scheduler.getEvent(event_id); event_obj = scheduler.getEvent(event_id);
} }
var self = this, var data = self.get_event_data(event_obj),
data = this.get_event_data(event_obj), fields_to_fetch = _(self.form_dialog.form.fields_view.fields).keys();
form = self.form_dialog.form, self.dataset.index = null;
fields_to_fetch = _(form.fields_view.fields).keys();
this.dataset.index = null;
self.creating_event_id = event_id; self.creating_event_id = event_id;
this.form_dialog.form.do_show().then(function() { self.form_dialog.form.do_show().then(function() {
_.each(['date_start', 'date_delay', 'date_stop'], function(field) { _.each(['date_start', 'date_delay', 'date_stop'], function(field) {
var field_name = self[field]; var field_name = self[field];
if (field_name && form.fields[field_name]) { if (field_name && self.form_dialog.form.fields[field_name]) {
var ffield = form.fields[field_name]; var ffield = self.form_dialog.form.fields[field_name];
ffield._dirty_flag = false; ffield._dirty_flag = false;
$.when(ffield.set_value(data[field_name])).then(function() { $.when(ffield.set_value(data[field_name])).then(function() {
ffield._dirty_flag = true; ffield._dirty_flag = true;
form.do_onchange(ffield); self.form_dialog.form.do_onchange(ffield);
}); });
} }
}); });
self.form_dialog.open(); self.form_dialog.open();
}); });
});
}, },
do_save_event: function(event_id, event_obj) { do_save_event: function(event_id, event_obj) {
var self = this, var self = this,
@ -451,12 +452,13 @@ instance.web_calendar.CalendarFormDialog = instance.web.Dialog.extend({
this.form = new instance.web.FormView(this, this.dataset, this.view_id, { this.form = new instance.web.FormView(this, this.dataset, this.view_id, {
pager: false pager: false
}); });
this.form.appendTo(this.$element); var def = this.form.appendTo(this.$element);
this.form.on_created.add_last(this.on_form_dialog_saved); this.form.on_created.add_last(this.on_form_dialog_saved);
this.form.on_saved.add_last(this.on_form_dialog_saved); this.form.on_saved.add_last(this.on_form_dialog_saved);
this.form.on_button_cancel = function() { this.form.on_button_cancel = function() {
self.close(); self.close();
} }
return def;
}, },
on_form_dialog_saved: function() { on_form_dialog_saved: function() {
var id = this.dataset.ids[this.dataset.index]; var id = this.dataset.ids[this.dataset.index];

View File

@ -1,3 +1,4 @@
@charset "utf-8";
.openerp .oe_kanban_view { .openerp .oe_kanban_view {
height: inherit; height: inherit;
} }
@ -44,8 +45,17 @@
.openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_groups { .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_groups {
width: 100%; width: 100%;
} }
.openerp .oe_kanban_view .oe_kanban_header:hover .oe_dropdown_kanban { .openerp .oe_kanban_view.oe_kanban_grouped_by_m2o .oe_kanban_group_title {
display: inline-block; cursor: move;
}
.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban {
float: right;
}
.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban > span {
visibility: hidden;
}
.openerp .oe_kanban_view .oe_kanban_header:hover .oe_dropdown_kanban > span {
visibility: visible;
} }
.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_menu { .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_menu {
font-weight: normal; font-weight: normal;
@ -59,7 +69,6 @@
text-shadow: 0 1px 0 white; text-shadow: 0 1px 0 white;
} }
.openerp .oe_kanban_view .oe_kanban_group_title > span { .openerp .oe_kanban_view .oe_kanban_group_title > span {
float: left;
margin-right: 4px; margin-right: 4px;
} }
.openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header { .openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header {
@ -93,6 +102,9 @@
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical { .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical {
display: block; display: block;
} }
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_dropdown_kanban {
left: -5px;
}
.openerp .oe_kanban_view .oe_kanban_group_title_undefined { .openerp .oe_kanban_view .oe_kanban_group_title_undefined {
color: #666666; color: #666666;
} }
@ -104,20 +116,11 @@
-ms-transform: rotate(90deg); -ms-transform: rotate(90deg);
transform: rotate(90deg); transform: rotate(90deg);
width: 30px; width: 30px;
height: 20px;
font-size: 24px; font-size: 24px;
white-space: nowrap; white-space: nowrap;
display: none; display: none;
position: absolute; position: relative;
top: 10px; top: 5px;
}
.openerp .oe_kanban_view .oe_kanban_fold_icon {
cursor: pointer;
float: left;
padding: 2px;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat;
} }
.openerp .oe_kanban_view .oe_kanban_add, .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle { .openerp .oe_kanban_view .oe_kanban_add, .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle {
margin-left: 4px; margin-left: 4px;
@ -462,13 +465,10 @@
top: 28px; top: 28px;
min-width: 160px; min-width: 160px;
} }
.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban { .openerp .oe_kanban_view .oe_dropdown_kanban.oe_opened > span {
display: none;
}
.openerp .oe_kanban_view .oe_kanban_column .oe_dropdown_kanban.oe_opened > span {
visibility: visible; visibility: visible;
} }
.openerp .oe_kanban_view .oe_kanban_column .oe_dropdown_kanban > span { .openerp .oe_kanban_view .oe_dropdown_kanban > span {
visibility: hidden; visibility: hidden;
} }
.openerp .oe_kanban_view .oe_kanban_colorpicker { .openerp .oe_kanban_view .oe_kanban_colorpicker {

View File

@ -66,10 +66,16 @@
height: inherit height: inherit
&.oe_kanban_ungrouped .oe_kanban_groups &.oe_kanban_ungrouped .oe_kanban_groups
width: 100% width: 100%
&.oe_kanban_grouped_by_m2o .oe_kanban_group_title
cursor: move
.oe_kanban_header .oe_kanban_header
&:hover
.oe_dropdown_kanban .oe_dropdown_kanban
display: inline-block float: right
.oe_dropdown_kanban > span
visibility: hidden
&:hover
.oe_dropdown_kanban > span
visibility: visible
.oe_dropdown_menu .oe_dropdown_menu
font-weight: normal font-weight: normal
font-size: 13px font-size: 13px
@ -80,7 +86,6 @@
color: #333333 color: #333333
text-shadow: 0 1px 0 white text-shadow: 0 1px 0 white
> span > span
float: left
margin-right: 4px margin-right: 4px
.oe_kanban_column, .oe_kanban_group_header .oe_kanban_column, .oe_kanban_group_header
@ -111,6 +116,8 @@
display: none display: none
.oe_kanban_group_title_vertical .oe_kanban_group_title_vertical
display: block display: block
.oe_dropdown_kanban
left: -5px
.oe_kanban_group_title_undefined .oe_kanban_group_title_undefined
color: #666666 color: #666666
.oe_kanban_group_title_vertical .oe_kanban_group_title_vertical
@ -121,19 +128,11 @@
-ms-transform: rotate(90deg) -ms-transform: rotate(90deg)
transform: rotate(90deg) transform: rotate(90deg)
width: 30px width: 30px
height: 20px
font-size: 24px font-size: 24px
white-space: nowrap white-space: nowrap
display: none display: none
position: absolute position: relative
top: 10px top: 5px
.oe_kanban_fold_icon
cursor: pointer
float: left
padding: 2px
width: 16px
height: 16px
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat
// }}} // }}}
// KanbanQuickCreate {{{ // KanbanQuickCreate {{{
.oe_kanban_add, .oe_kanban_header .oe_dropdown_toggle .oe_kanban_add, .oe_kanban_header .oe_dropdown_toggle
@ -388,10 +387,6 @@
left: 0 left: 0
top: 28px top: 28px
min-width: 160px min-width: 160px
.oe_kanban_header
.oe_dropdown_kanban
display: none
.oe_kanban_column
.oe_dropdown_kanban .oe_dropdown_kanban
&.oe_opened > span &.oe_opened > span
visibility: visible visibility: visible

View File

@ -24,6 +24,8 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.fields_view = {}; this.fields_view = {};
this.fields_keys = []; this.fields_keys = [];
this.group_by = null; this.group_by = null;
this.group_by_field = {};
this.grouped_by_m2o = false;
this.state = { this.state = {
groups : {}, groups : {},
records : {} records : {}
@ -54,7 +56,8 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.$element.find('.oe_kanban_buttons').replaceWith(this.$buttons); this.$element.find('.oe_kanban_buttons').replaceWith(this.$buttons);
} }
this.$buttons this.$buttons
.on('click','button.oe_kanban_button_new', this.do_add_record); .on('click', 'button.oe_kanban_button_new', this.do_add_record)
.on('click', '.oe_kanban_add_column', this.do_add_group);
this.$groups = this.$element.find('.oe_kanban_groups tr'); this.$groups = this.$element.find('.oe_kanban_groups tr');
this.fields_keys = _.keys(this.fields_view.fields); this.fields_keys = _.keys(this.fields_view.fields);
this.add_qweb_template(); this.add_qweb_template();
@ -157,6 +160,39 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.dataset.index = null; this.dataset.index = null;
this.do_switch_view('form'); this.do_switch_view('form');
}, },
do_add_group: function() {
var self = this;
self.do_action({
name: _t("Add column"),
res_model: self.group_by_field.relation,
views: [[false, 'form']],
type: 'ir.actions.act_window',
target: "new",
flags: {
action_buttons: true,
}
});
var am = instance.webclient.action_manager;
var form = am.dialog_widget.views.form.controller;
form.on_button_cancel.add_last(am.dialog.on_close);
form.on_created.add_last(function(r) {
(new instance.web.DataSet(self, self.group_by_field.relation)).name_get([r.result]).then(function(new_record) {
am.dialog.on_close();
var domain = self.dataset.domain.slice(0);
domain.push([self.group_by, '=', new_record[0][0]]);
var dataset = new instance.web.DataSetSearch(self, self.dataset.model, self.dataset.get_context(), domain);
var datagroup = {
value: new_record[0],
length: 0,
aggregates: {},
};
var new_group = new instance.web_kanban.KanbanGroup(self, [], datagroup, dataset);
self.do_add_groups([new_group]).then(function() {
$(window).scrollTo(self.groups.slice(-1)[0].$element, { axis: 'x' });
});
});
});
},
do_search: function(domain, context, group_by) { do_search: function(domain, context, group_by) {
var self = this; var self = this;
this.$element.find('.oe_view_nocontent').remove(); this.$element.find('.oe_view_nocontent').remove();
@ -165,6 +201,10 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.search_group_by = group_by; this.search_group_by = group_by;
$.when(this.has_been_loaded).then(function() { $.when(this.has_been_loaded).then(function() {
self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by; self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by;
self.group_by_field = self.fields_view.fields[self.group_by] || {};
self.grouped_by_m2o = (self.group_by_field.type === 'many2one');
self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o);
self.$element.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o);
self.datagroup = new instance.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []); self.datagroup = new instance.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []);
self.datagroup.list(self.fields_keys, self.do_process_groups, self.do_process_dataset); self.datagroup.list(self.fields_keys, self.do_process_groups, self.do_process_dataset);
}); });
@ -227,7 +267,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
self.groups[group.undefined_title ? 'unshift' : 'push'](group); self.groups[group.undefined_title ? 'unshift' : 'push'](group);
}); });
var groups_started = _.map(this.groups, function(group) { var groups_started = _.map(this.groups, function(group) {
if (!group.is_started) {
return group.insertBefore(self.$element.find('.oe_kanban_groups_headers td:last')); return group.insertBefore(self.$element.find('.oe_kanban_groups_headers td:last'));
}
}); });
return $.when.apply(null, groups_started).then(function () { return $.when.apply(null, groups_started).then(function () {
self.on_groups_started(); self.on_groups_started();
@ -237,6 +279,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
var self = this; var self = this;
this.compute_groups_width(); this.compute_groups_width();
if (this.group_by) { if (this.group_by) {
// Kanban cards drag'n'drop
this.$element.find('.oe_kanban_column').sortable({ this.$element.find('.oe_kanban_column').sortable({
connectWith: '.oe_kanban_column', connectWith: '.oe_kanban_column',
handle : '.oe_kanban_draghandle', handle : '.oe_kanban_draghandle',
@ -245,17 +288,50 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
self.currently_dragging.group = ui.item.parents('.oe_kanban_column:first').data('widget'); self.currently_dragging.group = ui.item.parents('.oe_kanban_column:first').data('widget');
}, },
stop: function(event, ui) { stop: function(event, ui) {
var record = ui.item.data('widget'), var record = ui.item.data('widget');
old_index = self.currently_dragging.index, var old_index = self.currently_dragging.index;
new_index = ui.item.index(), var new_index = ui.item.index();
old_group = self.currently_dragging.group, var old_group = self.currently_dragging.group;
new_group = ui.item.parents('.oe_kanban_column:first').data('widget'); var new_group = ui.item.parents('.oe_kanban_column:first').data('widget');
if (!(old_group.title === new_group.title && old_group.value === new_group.value && old_index == new_index)) { if (!(old_group.title === new_group.title && old_group.value === new_group.value && old_index == new_index)) {
self.on_record_moved(record, old_group, old_index, new_group, new_index); self.on_record_moved(record, old_group, old_index, new_group, new_index);
} }
}, },
scroll: false scroll: false
}); });
// Kanban groups drag'n'drop
var start_index;
if (this.grouped_by_m2o) {
this.$('.oe_kanban_groups_headers').sortable({
items: '.oe_kanban_group_header',
helper: 'clone',
axis: 'x',
opacity: 0.5,
scroll: false,
start: function(event, ui) {
start_index = ui.item.index();
self.$('.oe_kanban_record').css({ visibility: 'hidden' });
},
stop: function(event, ui) {
var stop_index = ui.item.index();
if (start_index !== stop_index) {
var $start_column = $('.oe_kanban_groups_records .oe_kanban_column').eq(start_index);
var $stop_column = $('.oe_kanban_groups_records .oe_kanban_column').eq(stop_index);
var method = (start_index > stop_index) ? 'insertBefore' : 'insertAfter';
$start_column[method]($stop_column);
var tmp_group = self.groups.splice(start_index, 1)[0];
self.groups.splice(stop_index, 0, tmp_group);
var new_sequence = _.pluck(self.groups, 'value');
(new instance.web.DataSet(self, self.group_by_field.relation)).resequence(new_sequence).then(function(r) {
if (r === false) {
console.error("Kanban: could not resequence model '%s'. Probably no 'sequence' field.", self.group_by_field.relation);
}
});
}
self.$('.oe_kanban_record').css({ visibility: 'visible' });
}
});
}
} else { } else {
this.$element.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle'); this.$element.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle');
} }
@ -289,7 +365,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
var self = this; var self = this;
_.each(this.groups, function(group) { _.each(this.groups, function(group) {
unfolded += group.state.folded ? 0 : 1; unfolded += group.state.folded ? 0 : 1;
group.$element.css('width', ''); group.$element.children(':first').css('width', '');
}); });
_.each(this.groups, function(group) { _.each(this.groups, function(group) {
if (!group.state.folded) { if (!group.state.folded) {
@ -321,7 +397,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
}, },
open_record: function(id, editable) { open_record: function(id, editable) {
if (this.dataset.select_id(id)) { if (this.dataset.select_id(id)) {
this.do_switch_view('form', null, { editable: editable }); this.do_switch_view('form', null, { mode: editable ? "edit" : undefined });
} else { } else {
this.do_warn("Kanban: could not find id#" + id); this.do_warn("Kanban: could not find id#" + id);
} }
@ -362,8 +438,8 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
this.title = this.value[1]; this.title = this.value[1];
this.value = this.value[0]; this.value = this.value[0];
} }
var field = this.view.fields_view.fields[this.view.group_by]; var field = this.view.group_by_field;
if (field) { if (!_.isEmpty(field)) {
try { try {
this.title = instance.web.format_value(group.value, field, false); this.title = instance.web.format_value(group.value, field, false);
} catch(e) {} } catch(e) {}
@ -402,11 +478,14 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
} }
this.$records = $(QWeb.render('KanbanView.group_records_container', { widget : this})); this.$records = $(QWeb.render('KanbanView.group_records_container', { widget : this}));
this.$records.insertBefore(this.view.$element.find('.oe_kanban_groups_records td:last')); this.$records.insertBefore(this.view.$element.find('.oe_kanban_groups_records td:last'));
this.$element.find(".oe_kanban_fold_icon").click(function() {
self.do_toggle_fold(); this.$element.on('click', '.oe_kanban_group_dropdown li a', function(ev) {
self.view.compute_groups_width(); var fn = 'do_action_' + $(ev.target).data().action;
return false; if (typeof(self[fn]) === 'function') {
self[fn]($(ev.target));
}
}); });
this.$element.find('.oe_kanban_add').click(function () { this.$element.find('.oe_kanban_add').click(function () {
if (self.quick) { return; } if (self.quick) { return; }
var ctx = {}; var ctx = {};
@ -433,26 +512,27 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
this.$records.click(function (ev) { this.$records.click(function (ev) {
if (ev.target == ev.currentTarget) { if (ev.target == ev.currentTarget) {
if (!self.state.folded) { if (!self.state.folded) {
add_btn.effect('bounce', {distance: 18, times: 5}, 150) add_btn.effect('bounce', {distance: 18, times: 5}, 150);
} }
} }
}); });
this.is_started = true;
return def; return def;
}, },
compute_cards_auto_height: function() { compute_cards_auto_height: function() {
// oe_kanban_auto_height is an empty class used by the kanban view in order // oe_kanban_no_auto_height is an empty class used to disable this feature
// to normalize height amongst kanban cards. (by group) if (!this.view.group_by) {
var self = this;
var min_height = 0; var min_height = 0;
var els = []; var els = [];
_.each(this.records, function(r) { _.each(this.records, function(r) {
var $e = r.$element.find('.oe_kanban_auto_height').first().css('min-height', 0); var $e = r.$element.children(':first:not(.oe_kanban_no_auto_height)').css('min-height', 0);
if ($e.length) { if ($e.length) {
els.push($e[0]); els.push($e[0]);
min_height = Math.max(min_height, $e.outerHeight()); min_height = Math.max(min_height, $e.outerHeight());
} }
}); });
$(els).css('min-height', min_height); $(els).css('min-height', min_height);
}
}, },
destroy: function() { destroy: function() {
this._super(); this._super();
@ -493,13 +573,46 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
do_toggle_fold: function(compute_width) { do_toggle_fold: function(compute_width) {
this.$element.add(this.$records).toggleClass('oe_kanban_group_folded'); this.$element.add(this.$records).toggleClass('oe_kanban_group_folded');
this.state.folded = this.$element.is('.oe_kanban_group_folded'); this.state.folded = this.$element.is('.oe_kanban_group_folded');
this.$("ul.oe_kanban_group_dropdown li a[data-action=toggle_fold]").text((this.state.folded) ? _t("Unfold") : _t("Fold"));
},
do_action_toggle_fold: function() {
this.do_toggle_fold();
this.view.compute_groups_width();
},
do_action_edit: function() {
var self = this;
self.do_action({
res_id: this.group.value[0],
name: _t("Edit column"),
res_model: self.view.group_by_field.relation,
views: [[false, 'form']],
type: 'ir.actions.act_window',
target: "new",
flags: {
action_buttons: true,
}
});
var am = instance.webclient.action_manager;
var form = am.dialog_widget.views.form.controller;
form.on_button_cancel.add_last(am.dialog.on_close);
form.on_saved.add_last(function() {
am.dialog.on_close();
self.view.do_reload();
});
},
do_action_delete: function() {
var self = this;
if (confirm(_t("Are you sure to remove this column ?"))) {
(new instance.web.DataSet(self, self.view.group_by_field.relation)).unlink([self.group.value[0]]).then(function(r) {
self.view.do_reload();
});
}
}, },
do_save_sequences: function() { do_save_sequences: function() {
var self = this; var self = this;
if (_.indexOf(this.view.fields_keys, 'sequence') > -1) { if (_.indexOf(this.view.fields_keys, 'sequence') > -1) {
_.each(this.records, function(record, index) { var new_sequence = _.pluck(this.records, 'id');
self.view.dataset.write(record.id, { sequence : index }); self.view.dataset.resequence(new_sequence);
});
} }
}, },
/** /**
@ -720,7 +833,7 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).then(function(records) { this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).then(function(records) {
if (records.length) { if (records.length) {
self.set_record(records[0]); self.set_record(records[0]);
self.replaceElement($(self.render())); self.renderElement();
self.$element.data('widget', self); self.$element.data('widget', self);
self.bind_events(); self.bind_events();
self.group.compute_cards_auto_height(); self.group.compute_cards_auto_height();

View File

@ -18,6 +18,10 @@
<button type="button" class="oe_kanban_button_new oe_highlight"> <button type="button" class="oe_kanban_button_new oe_highlight">
<t t-esc="widget.options.create_text || _t('Create')"/> <t t-esc="widget.options.create_text || _t('Create')"/>
</button> </button>
<span class="oe_alternative" style="display: none">
<span class="oe_fade">or</span>
<a href="#" class="oe_bold oe_kanban_add_column">Add a new column</a>
</span>
</t> </t>
</t> </t>
</div> </div>
@ -28,18 +32,20 @@
<t t-if="widget.view._is_quick_create_enabled() and widget.view._is_action_enabled('create')"> <t t-if="widget.view._is_quick_create_enabled() and widget.view._is_action_enabled('create')">
<div class="oe_kanban_add oe_e">]</div> <div class="oe_kanban_add oe_e">]</div>
</t> </t>
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu oe_kanban_group_dropdown">
<li><a data-action="toggle_fold" href="#">Fold</a></li>
<t t-if="widget.view.grouped_by_m2o and widget.value">
<li><a data-action="edit" href="#">Edit</a></li>
<li><a data-action="delete" href="#">Delete</a></li>
</t>
</ul>
</div>
<div class="oe_fold_column"> <div class="oe_fold_column">
<div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}"> <div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}">
<span><t t-esc="widget.title"/></span> <span><t t-esc="widget.title"/></span>
<span class="oe_kanban_group_length">(<t t-esc="widget.group.length"/>)</span> <span class="oe_kanban_group_length">(<t t-esc="widget.group.length"/>)</span>
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li><a data-type="fold" href="#" class="">Fold</a></li>
<li><a data-type="edit" href="#" class="">Edit</a></li>
<li><a data-type="delete" href="#" class="">Delete</a></li>
</ul>
</div>
</div> </div>
<div class="oe_clear"/> <div class="oe_clear"/>
<ul class="oe_kanban_aggregates"> <ul class="oe_kanban_aggregates">
@ -48,7 +54,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<p t-if="widget.title" class="oe_kanban_group_title_vertical"><t t-esc="widget.title"/></p> <span t-if="widget.title" class="oe_kanban_group_title_vertical"><t t-esc="widget.title"/></span>
</div> </div>
</t> </t>
<t t-if="! widget.view.group_by &amp;&amp; widget.view._is_quick_create_enabled()"> <t t-if="! widget.view.group_by &amp;&amp; widget.view._is_quick_create_enabled()">

View File

@ -70,11 +70,10 @@ instance.web_view_editor.ViewEditor = instance.web.Widget.extend({
this.view_edit_dialog.on_close.add_last(function(){window.location.reload();}); this.view_edit_dialog.on_close.add_last(function(){window.location.reload();});
this.main_view_id = this.parent.fields_view.view_id; this.main_view_id = this.parent.fields_view.view_id;
this.action_manager = new instance.web.ActionManager(this); this.action_manager = new instance.web.ActionManager(this);
this.action_manager.appendTo(this.view_edit_dialog.$element);
$.when(this.action_manager.do_action(action)).then(function() { $.when(this.action_manager.do_action(action)).then(function() {
var viewmanager = self.action_manager.inner_widget, var viewmanager = self.action_manager.inner_widget;
controller = viewmanager.views[viewmanager.active_view].controller; var controller = viewmanager.views[viewmanager.active_view].controller;
self.action_manager.appendTo(self.view_edit_dialog.$element);
self.action_manager.renderElement(self.view_edit_dialog);
controller.on_loaded.add_last(function(){ controller.on_loaded.add_last(function(){
$(controller.groups).bind({ $(controller.groups).bind({
'selected': function(e, ids, records) { 'selected': function(e, ids, records) {