-openerp.web.list = function (instance) {
+(function() {
+
+var instance = openerp;
+openerp.web.list = {};
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
this.groups = groups;
$(this.groups).bind({
- 'selected': function (e, ids, records) {
- self.do_select(ids, records);
+ 'selected': function (e, ids, records, deselected) {
+ self.do_select(ids, records, deselected);
},
'deleted': function (e, ids) {
self.do_delete(ids);
* @returns {String} CSS style declaration
*/
style_for: function (record) {
- var style= '';
+ var len, style= '';
var context = _.extend({}, record.attributes, {
uid: this.session.uid,
- current_date: new Date().toString('yyyy-MM-dd')
+ current_date: moment().format('YYYY-MM-DD')
// TODO: time, datetime, relativedelta
});
-
+ var i;
+ var pair;
+ var expression;
if (this.fonts) {
- for(var i=0, len=this.fonts.length; i<len; ++i) {
- var pair = this.fonts[i],
- font = pair[0],
+ for(i=0, len=this.fonts.length; i<len; ++i) {
+ pair = this.fonts[i];
+ var font = pair[0];
expression = pair[1];
if (py.evaluate(expression, context).toJSON()) {
switch(font) {
}
if (!this.colors) { return style; }
- for(var i=0, len=this.colors.length; i<len; ++i) {
- var pair = this.colors[i],
- color = pair[0],
- expression = pair[1];
+ for(i=0, len=this.colors.length; i<len; ++i) {
+ pair = this.colors[i];
+ var color = pair[0];
+ expression = pair[1];
if (py.evaluate(expression, context).toJSON()) {
return style += 'color: ' + color + ';';
}
// Pager
if (!this.$pager) {
- this.$pager = $(QWeb.render("ListView.pager", {'widget':self}));
+ this.$pager = $(QWeb.render("ListView.pager", {'widget':self})).hide();
if (this.options.$buttons) {
this.$pager.appendTo(this.options.$pager);
} else {
this.sidebar.$el.hide();
}
//Sort
+ var default_order = this.fields_view.arch.attrs.default_order,
+ unsorted = !this.dataset._sort.length;
+ if (unsorted && default_order) {
+ this.dataset.set_sort(default_order.split(','));
+ }
+
if(this.dataset._sort.length){
if(this.dataset._sort[0].indexOf('-') == -1){
this.$el.find('th[data-id=' + this.dataset._sort[0] + ']').addClass("sortdown");
sort_by_column: function (e) {
e.stopPropagation();
var $column = $(e.currentTarget);
- var col_name = $column.data('id')
+ var col_name = $column.data('id');
var field = this.fields_view.fields[col_name];
- // test if the field is a function field with store=false, since it's impossible
- // for the server to sort those fields we desactivate the feature
- if (field && field.store === false) {
+ // test whether the field is sortable
+ if (field && !field.sortable) {
return false;
}
this.dataset.sort(col_name);
var total = dataset.size();
var limit = this.limit() || total;
- if (total == 0)
- this.$pager.hide();
- else
- this.$pager.css("display", "");
- this.$pager.toggleClass('oe_list_pager_single_page', (total <= limit));
+ this.$pager.find('.oe-pager-button').toggle(total > limit);
+ this.$pager.find('.oe_pager_value').toggle(total !== 0);
var spager = '-';
if (total) {
var range_start = this.page * limit + 1;
* @param {String} [view="page"] the view type to switch to
*/
select_record:function (index, view) {
- view = view || index == null ? 'form' : 'form';
+ view = view || index === null || index === undefined ? 'form' : 'form';
this.dataset.index = index;
_.delay(_.bind(function () {
this.do_switch_view(view);
self.$el.find('.oe_list_record_selector').prop('checked', false);
this.records.reset();
var reloaded = $.Deferred();
+ reloaded.then(function () {
+ if (!self.grouped) self.$pager.show();
+ });
this.$el.find('.oe_list_content').append(
this.groups.render(function () {
if (self.dataset.index == null) {
},
reload_record: function (record) {
var self = this;
- // Use of search_read instead of read to check if we can still read the record (security rules)
+ var fields = this.fields_view.fields;
return this.dataset.read_ids(
[record.get('id')],
_.pluck(_(this.columns).filter(function (r) {
self.records.remove(record);
return;
}
- _(_.keys(values)).each(function(key){
- record.set(key, values[key], {silent: true});
+ _.each(values, function (value, key) {
+ if (fields[key] && fields[key].type === 'many2many')
+ record.set(key + '__display', false, {silent: true});
+ record.set(key, value, {silent: true});
});
record.trigger('change', record);
});
* @param {Array} ids selected record ids
* @param {Array} records selected record values
*/
- do_select: function (ids, records) {
+ do_select: function (ids, records, deselected) {
+ // uncheck header hook if at least one row has been deselected
+ if (deselected) {
+ this.$('.oe_list_record_selector').prop('checked', false);
+ }
+
if (!ids.length) {
this.dataset.index = 0;
if (this.sidebar) {
return ids;
},
/**
+ * Calculate the active domain of the list view. This should be done only
+ * if the header checkbox has been checked. This is done by evaluating the
+ * search results, and then adding the dataset domain (i.e. action domain).
+ */
+ get_active_domain: function () {
+ var self = this;
+ if (this.$('.oe_list_record_selector').prop('checked')) {
+ var search_view = this.getParent().searchview;
+ var search_data = search_view.build_search_data();
+ return instance.web.pyeval.eval_domains_and_contexts({
+ domains: search_data.domains,
+ contexts: search_data.contexts,
+ group_by_seq: search_data.groupbys || []
+ }).then(function (results) {
+ var domain = self.dataset.domain.concat(results.domain || []);
+ return domain
+ });
+ }
+ else {
+ return $.Deferred().resolve();
+ }
+ },
+ /**
* Adds padding columns at the start or end of all table rows (including
* field names row)
*
this.$el.prepend(
$('<div class="oe_view_nocontent">').html(this.options.action.help)
);
- var create_nocontent = this.$buttons;
+ var $buttons = this.$buttons;
this.$el.find('.oe_view_nocontent').click(function() {
- create_nocontent.openerpBounce();
+ $buttons.width($buttons.width() + 1).openerpBounce();
});
}
});
.delegate('th.oe_list_record_selector', 'click', function (e) {
e.stopPropagation();
var selection = self.get_selection();
+ var checked = $(e.currentTarget).find('input').prop('checked');
$(self).trigger(
- 'selected', [selection.ids, selection.records]);
+ 'selected', [selection.ids, selection.records, ! checked]);
})
.delegate('td.oe_list_record_delete button', 'click', function (e) {
e.stopPropagation();
if (column.invisible === '1') {
return;
}
- if (column.tag === 'button') {
- cells.push('<td class="oe_button" title="' + column.string + '"> </td>');
- } else {
- cells.push('<td title="' + column.string + '"> </td>');
- }
+ cells.push('<td title="' + column.string + '"> </td>');
});
if (this.options.deletable) {
cells.push('<td class="oe_list_record_delete"><button type="button" style="visibility: hidden"> </button></td>');
bind_child_events: function (child) {
var $this = $(this),
self = this;
- $(child).bind('selected', function (e) {
+ $(child).bind('selected', function (e, _0, _1, deselected) {
// can have selections spanning multiple links
var selection = self.get_selection();
- $this.trigger(e, [selection.ids, selection.records]);
+ $this.trigger(e, [selection.ids, selection.records, deselected]);
}).bind(this.passthrough_events, function (e) {
// additional positional parameters are provided to trigger as an
// Array, following the event type or event object, but are
limit = view.limit(),
page = this.datagroup.openable ? this.page : view.page;
- var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
+ var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name');
var options = { offset: page * limit, limit: limit, context: {bin_size: true} };
//TODO xmo: investigate why we need to put the setTimeout
return $.async_when().then(function() {
}))
.end()
.find('button[data-pager-action=previous]')
- .css('visibility',
- page === 0 ? 'hidden' : '')
+ .toggleClass('disabled', page === 0)
.end()
.find('button[data-pager-action=next]')
- .css('visibility',
- page === pages - 1 ? 'hidden' : '');
+ .toggleClass('disabled', page === pages - 1);
}
}
// if drag to 1st row (to = 0), start sequencing from 0
// (exclusive lower bound)
seq = to ? list.records.at(to - 1).get(seqname) : 0;
- while (++seq, record = list.records.at(index++)) {
+ var fct = function (dataset, id, seq) {
+ $.async_when().done(function () {
+ var attrs = {};
+ attrs[seqname] = seq;
+ dataset.write(id, attrs);
+ });
+ };
+ while (++seq, (record = list.records.at(index++))) {
// write are independent from one another, so we can just
// launch them all at the same time and we don't really
// give a fig about when they're done
// FIXME: breaks on o2ms (e.g. Accounting > Financial
// Accounting > Taxes > Taxes, child tax accounts)
// when synchronous (without setTimeout)
- (function (dataset, id, seq) {
- $.async_when().done(function () {
- var attrs = {};
- attrs[seqname] = seq;
- dataset.write(id, attrs);
- });
- }(dataset, record.get('id'), seq));
+ fct(dataset, record.get('id'), seq);
record.set(seqname, seq);
}
}
this.datagroup.list(
_(this.view.visible_columns).chain()
- .filter(function (column) { return column.tag === 'field' })
+ .filter(function (column) { return column.tag === 'field';})
.pluck('name').value(),
function (groups) {
self.view.$pager.hide();
self.setup_resequence_rows(list, dataset);
}).always(function() {
if (post_render) { post_render(); }
+ self.view.trigger('view_list_rendered');
});
});
return $el;
return {
count: this.datagroup.length,
values: this.datagroup.aggregates
- }
+ };
}
return _(this.children).chain()
.map(function (child) {
var instance_ = (records[i] instanceof Record) ? records[i] : new Record(records[i]);
instance_.bind(null, this._onRecordEvent);
this._byId[instance_.get('id')] = instance_;
- if (options.at == undefined) {
+ if (options.at === undefined || options.at === null) {
this.records.push(instance_);
if (!options.silent) {
this.trigger('add', this, instance_, this.records.length-1);
if (!_(this._proxies).isEmpty()) {
var record = null;
_(this._proxies).detect(function (proxy) {
- return record = proxy.get(id);
+ record = proxy.get(id);
+ return record;
});
return record;
}
* @returns {Collection}
*/
proxy: function (section) {
- return this._proxies[section] = new Collection(null, {
+ this._proxies[section] = new Collection(null, {
parent: this,
key: section
}).bind(null, this._onRecordEvent);
+ return this._proxies[section];
},
/**
* @param {Array} [records]
var record;
for(var section in this._proxies) {
if (!this._proxies.hasOwnProperty(section)) {
- continue
+ continue;
}
if ((record = this._proxies[section].find(callback))) {
return record;
'field': 'instance.web.list.Column',
'field.boolean': 'instance.web.list.Boolean',
'field.binary': 'instance.web.list.Binary',
+ 'field.char': 'instance.web.list.Char',
'field.progressbar': 'instance.web.list.ProgressBar',
'field.handle': 'instance.web.list.Handle',
'button': 'instance.web.list.Button',
'field.many2onebutton': 'instance.web.list.Many2OneButton',
'field.reference': 'instance.web.list.Reference',
- 'field.many2many': 'instance.web.list.Many2Many'
+ 'field.many2many': 'instance.web.list.Many2Many',
+ 'button.toggle_button': 'instance.web.list.toggle_button',
});
instance.web.list.columns.for_ = function (id, field, node) {
var description = _.extend({tag: node.tag}, field, node.attrs);
tag + '.'+ description.type,
tag
]);
- return new Type(id, node.tag, description)
+ return new Type(id, node.tag, description);
};
instance.web.list.Column = instance.web.Class.extend({
attrs = this.modifiers_for(row_data);
}
if (attrs.invisible) { return ''; }
-
- return QWeb.render('ListView.row.button', {
+ var template = this.icon && 'ListView.row.button' || 'ListView.row.text_button';
+ return QWeb.render(template, {
widget: this,
prefix: instance.session.prefix,
disabled: attrs.readonly
});
}
});
+instance.web.list.Char = instance.web.list.Column.extend({
+ replacement: '*',
+ /**
+ * If password field, only display replacement characters (if value is
+ * non-empty)
+ */
+ _format: function (row_data, options) {
+ var value = row_data[this.id].value;
+ if (value && this.password === 'True') {
+ return value.replace(/[\s\S]/g, _.escape(this.replacement));
+ }
+ return this._super(row_data, options);
+ }
+});
instance.web.list.ProgressBar = instance.web.list.Column.extend({
/**
* Return a formatted progress bar display
return this._super(row_data, options);
}
});
-};
-// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
+instance.web.list.toggle_button = instance.web.list.Column.extend({
+ format: function (row_data, options) {
+ this._super(row_data, options);
+ var button_tips = JSON.parse(this.options);
+ var fieldname = this.field_name;
+ var has_value = row_data[fieldname] && !!row_data[fieldname].value;
+ this.icon = has_value ? 'gtk-yes' : 'gtk-normal';
+ this.string = has_value ? _t(button_tips ? button_tips['active']: ''): _t(button_tips ? button_tips['inactive']: '');
+ return QWeb.render('toggle_button', {
+ widget: this,
+ prefix: instance.session.prefix,
+ });
+ },
+});
+})();