summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/list_view.js
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2016-04-08 14:53:34 +0200
committerGéry Debongnie <ged@odoo.com>2016-04-21 15:21:39 +0200
commit977db823c7c84e9edc7c8cf8384eb9cf47275b3a (patch)
treec3312f745baf11d51f976a60d6e285480f557d4c /addons/web/static/src/js/views/list_view.js
parente1bfd3fbda97ac7a64a585b07be161d5be606cf9 (diff)
[REF] web: stop duplicating web
Avoid duplicating web addon in enterprise by extracting a common basis. Enterprise features stay in enterprise, but use that common basis. Mainly: - JS refactoring and linting - Conversion of .sass into .less split into multiple files - Templates cleaning and DOM simplification - Re-generation of web.pot, and update of .po files
Diffstat (limited to 'addons/web/static/src/js/views/list_view.js')
-rw-r--r--addons/web/static/src/js/views/list_view.js543
1 files changed, 237 insertions, 306 deletions
diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js
index d42d34a98d2..9214eb27152 100644
--- a/addons/web/static/src/js/views/list_view.js
+++ b/addons/web/static/src/js/views/list_view.js
@@ -8,6 +8,7 @@ var DataExport = require('web.DataExport');
var formats = require('web.formats');
var common = require('web.list_common');
var Model = require('web.DataModel');
+var Pager = require('web.Pager');
var pyeval = require('web.pyeval');
var session = require('web.session');
var Sidebar = require('web.Sidebar');
@@ -34,8 +35,7 @@ var row_decoration = [
var ListView = View.extend({
_template: 'ListView',
- accesskey: 'L',
- display_name: _lt('List'),
+ accesskey: "L",
defaults: _.extend({}, View.prototype.defaults, {
// records can be selected one by one
selectable: true,
@@ -54,8 +54,14 @@ var ListView = View.extend({
//whether the editable property of the view has to be disabled
disable_editable_mode: false,
}),
+ display_name: _lt('List'),
events: {
- 'click thead th.oe_sortable[data-id]': 'sort_by_column'
+ 'click thead th.o_column_sortable[data-id]': 'sort_by_column',
+ 'click .oe_view_nocontent': function() {
+ if (this.$buttons) {
+ this.$buttons.width(this.$buttons.width() + 1).openerpBounce();
+ }
+ },
},
icon: 'fa-list-ul',
@@ -92,8 +98,7 @@ var ListView = View.extend({
});
this.previous_colspan = null;
- this.colors = null;
- this.fonts = null;
+ this.decoration = null;
this.columns = [];
@@ -111,7 +116,6 @@ var ListView = View.extend({
this.groups.datagroup.sort = this.dataset._sort;
}
- this.page = 0;
this.records.bind('change', function (event, record, key) {
if (!_(self.aggregate_columns).chain()
.pluck('name').contains(key).value()) {
@@ -127,6 +131,7 @@ var ListView = View.extend({
this.options.$pager = false;
}
+ this.options.deletable = this.options.deletable && this.is_action_enabled('delete');
this.name = "" + this.fields_view.arch.attrs.string;
// the view's number of records per page (|| section)
@@ -135,14 +140,26 @@ var ListView = View.extend({
(this.getParent().action || {}).limit ||
parseInt(this.fields_view.arch.attrs.limit, 10) ||
80);
+ // the index of the first displayed record (starting from 1)
+ this.current_min = 1;
- //Sort
- var default_order = this.fields_view.arch.attrs.default_order,
- unsorted = !this.dataset._sort.length;
+ // Sort
+ var default_order = this.fields_view.arch.attrs.default_order;
+ var unsorted = !this.dataset._sort.length;
if (unsorted && default_order && !this.grouped) {
this.dataset.set_sort(default_order.split(','));
}
},
+ willStart: function() {
+ // Retrieve the decoration defined on the model's list view
+ this.decoration = _.pick(this.fields_view.arch.attrs, function(value, key) {
+ return row_decoration.indexOf(key) >= 0;
+ });
+ this.decoration = _.mapObject(this.decoration, function(value) {
+ return py.parse(py.tokenize(value));
+ });
+ return this._super();
+ },
/**
* Set a custom Group construct as the root of the List View.
*
@@ -171,43 +188,6 @@ var ListView = View.extend({
}
});
},
- willStart: function() {
- // Retrieve the decoration defined on the model's list view
- this.decoration = _.pick(this.fields_view.arch.attrs, function(value, key) {
- return row_decoration.indexOf(key) >= 0;
- });
- this.decoration = _.mapObject(this.decoration, function(value) {
- return py.parse(py.tokenize(value));
- });
-
- this.setup_columns(this.fields_view.fields, this.grouped);
-
- return this._super();
- },
- start: function() {
- var self = this;
- this.$el.html(QWeb.render(this._template, this));
- this.$el.addClass(this.fields_view.arch.attrs['class']);
- this.$el.addClass('oe_list o_list_view');
-
- // Selecting records
- this.$('.oe_list_record_selector').click(function() {
- var checked = self.$('.oe_list_record_selector').prop('checked');
- self.$('.oe_list_record_selector input').prop('checked', checked || false);
- var selection = self.groups.get_selection();
- $(self.groups).trigger('selected', [selection.ids, selection.records]);
- });
-
- if(this.dataset._sort.length){
- if(this.dataset._sort[0].indexOf('-') === -1){
- this.$el.find('th[data-id=' + this.dataset._sort[0] + ']').addClass("sortdown");
- }else {
- this.$el.find('th[data-id=' + this.dataset._sort[0].split('-')[1] + ']').addClass("sortup");
- }
- }
- this.trigger('list_view_loaded', data, this.grouped);
- return this._super();
- },
/**
* Computes and returns the classnames for the provided record (from the
* ``@decoration`` attribute)
@@ -231,24 +211,58 @@ var ListView = View.extend({
return classnames;
},
/**
+ * Renders the table itself and inserts its content
+ * Computes and displays the aggregates
+ * Hooks up the selection of records event
+ * Adds adequate classname on the sorted column
+ */
+ load_list: function() {
+ var self = this;
+
+ // Render the table and append its content
+ this.$el.html(QWeb.render(this._template, this));
+ this.$el.addClass(this.fields_view.arch.attrs['class']);
+ if (this.grouped) {
+ this.$('.o_list_view').addClass('o_list_view_grouped');
+ }
+ this.$('.o_list_view').append(this.groups.elements);
+
+ // Compute the aggregates and display them in the list's footer
+ this.compute_aggregates();
+
+ // Head hook
+ // Selecting records
+ this.$('thead .o_list_record_selector input').click(function() {
+ self.$('tbody .o_list_record_selector input').prop('checked', $(this).prop('checked') || false);
+ var selection = self.groups.get_selection();
+ $(self.groups).trigger('selected', [selection.ids, selection.records]);
+ });
+
+ // Sort
+ if (this.dataset._sort.length) {
+ if (this.dataset._sort[0].indexOf('-') === -1) {
+ this.$('th[data-id=' + this.dataset._sort[0] + ']').addClass("o-sort-down");
+ } else {
+ this.$('th[data-id=' + this.dataset._sort[0].split('-')[1] + ']').addClass("o-sort-up");
+ }
+ }
+
+ this.trigger('list_view_loaded', data, this.grouped);
+ return $.when();
+ },
+ /**
* Render the buttons according to the ListView.buttons template and
* add listeners on it.
* Set this.$buttons with the produced jQuery element
* @param {jQuery} [$node] a jQuery node where the rendered buttons should be inserted
* $node may be undefined, in which case the ListView inserts them into this.options.$buttons
- * or into a div of its template
+ * if it exists
*/
render_buttons: function($node) {
if (!this.$buttons) {
this.$buttons = $(QWeb.render("ListView.buttons", {'widget': this}));
-
this.$buttons.find('.o_list_button_add').click(this.proxy('do_add_record'));
-
- if ($node) {
- this.$buttons.appendTo($node);
- } else {
- this.$('.oe_list_buttons').replaceWith(this.$buttons);
- }
+ this.$buttons.appendTo($node);
}
},
/**
@@ -271,7 +285,7 @@ var ListView = View.extend({
this.is_action_enabled('delete') && { label: _t('Delete'), callback: this.do_delete_selected }
]));
- $node = $node || this.options.$sidebar || this.$('.oe_list_sidebar');
+ $node = $node || this.options.$sidebar;
this.sidebar.appendTo($node);
// Hide the sidebar by default (it will be shown as soon as a record is selected)
@@ -279,72 +293,52 @@ var ListView = View.extend({
}
},
/**
- * Render the pager according to the ListView.pager template and add listeners on it.
- * Set this.$pager with the produced jQuery element
- * @param {jQuery} [$node] a jQuery node where the rendered pager should be inserted
+ * Instantiate and render the pager and add listeners on it.
+ * Set this.pager
+ * @param {jQuery} [$node] a jQuery node where the pager should be inserted
* $node may be undefined, in which case the ListView inserts the pager into this.options.$pager
- * or into a div of its template
*/
- render_pager: function($node) {
- if (!this.$pager && this.options.pager) {
- var self = this;
-
- this.$pager = $(QWeb.render("ListView.pager", {'widget': self}));
- this.$pager
- .on('click', 'a[data-pager-action]', function () {
- var $this = $(this);
- var max_page_index = Math.ceil(self.dataset.size() / self._limit) - 1;
- switch ($this.data('pager-action')) {
- case 'first':
- self.page = 0;
- break;
- case 'last':
- self.page = max_page_index;
- break;
- case 'next':
- self.page += 1;
- break;
- case 'previous':
- self.page -= 1;
- break;
+ render_pager: function($node, options) {
+ if (!this.pager && this.options.pager) {
+ this.pager = new Pager(this, this.dataset.size(), 1, this._limit, options);
+ this.pager.appendTo($node || this.options.$pager);
+
+ this.pager.on('pager_changed', this, function (new_state) {
+ var self = this;
+ var limit_changed = (this._limit !== new_state.limit);
+
+ this._limit = new_state.limit;
+ this.current_min = new_state.current_min;
+ this.reload_content().then(function() {
+ // Reset the scroll position to the top on page changed only
+ if (!limit_changed) {
+ self.set_scrollTop(0);
+ self.trigger_up('scrollTo', {offset: 0});
}
- if (self.page < 0) {
- self.page = max_page_index;
- } else if (self.page > max_page_index) {
- self.page = 0;
- }
- self.reload_content();
- }).find('.oe_list_pager_state')
- .click(function (e) {
- e.stopPropagation();
- var $this = $(this);
-
- var $select = $('<select>')
- .appendTo($this.empty())
- .click(function (e) {e.stopPropagation();})
- .append('<option value="80">80</option>' +
- '<option value="200">200</option>' +
- '<option value="500">500</option>' +
- '<option value="2000">2000</option>' +
- '<option value="NaN">' + _t("Unlimited") + '</option>')
- .change(function () {
- var val = parseInt($select.val(), 10);
- self._limit = (isNaN(val) ? null : val);
- self.page = 0;
- self.reload_content();
- }).blur(function() {
- $(this).trigger('change');
- })
- .val(self._limit || 'NaN');
- });
- this.configure_pager(this.dataset);
-
- $node = $node || this.options.$pager;
- if ($node) {
- this.$pager.appendTo($node);
- } else {
- this.$('.oe_list_pager').replaceWith(this.$pager);
+ });
+ });
+ }
+ },
+ /**
+ * Updates the pager based on the provided dataset's information
+ *
+ * Horrifying side-effect: sets the dataset's data on this.dataset?
+ *
+ * @param {instance.web.DataSet} [dataset]
+ * @param {int} [current_min] the min pager value
+ */
+ update_pager: function (dataset, current_min) {
+ this.dataset.ids = dataset.ids;
+ // Not exactly clean
+ if (dataset._length !== undefined) {
+ this.dataset._length = dataset._length;
+ }
+ if (this.pager && !this.grouped) {
+ var new_state = { size: this.dataset.size(), limit: this._limit };
+ if (current_min) {
+ new_state.current_min = current_min;
}
+ this.pager.update_state(new_state);
}
},
sort_by_column: function (e) {
@@ -357,54 +351,14 @@ var ListView = View.extend({
return false;
}
this.dataset.sort(col_name);
- if($column.hasClass("sortdown") || $column.hasClass("sortup")) {
- $column.toggleClass("sortup sortdown");
+ if($column.hasClass("o-sort-down") || $column.hasClass("o-sort-up")) {
+ $column.toggleClass("o-sort-up o-sort-down");
} else {
- $column.addClass("sortdown");
- }
- $column.siblings('.oe_sortable').removeClass("sortup sortdown");
-
- this.reload_content();
- },
- /**
- * Configures the ListView pager based on the provided dataset's information
- *
- * Horrifying side-effect: sets the dataset's data on this.dataset?
- *
- * @param {instance.web.DataSet} dataset
- */
- configure_pager: function (dataset) {
- this.dataset.ids = dataset.ids;
- // Not exactly clean
- if (dataset._length) {
- this.dataset._length = dataset._length;
+ $column.addClass("o-sort-down");
}
- if (this.$pager) {
- if (this.grouped) {
- // page count is irrelevant on grouped page, replace by limit
- this.$pager.find('.oe-pager-buttons').hide();
- this.$pager.find('.oe_list_pager_state').text(this._limit || '∞');
- } else {
- var total = dataset.size();
- var limit = this._limit || total;
- this.$pager.find('.oe-pager-buttons').toggle(total > limit);
- this.$pager.find('.oe_pager_value').toggle(total !== 0);
- var spager = '-';
- if (total) {
- var range_start = this.page * limit + 1;
- var range_stop = range_start - 1 + limit;
- if (this.records.length) {
- range_stop = range_start - 1 + this.records.length;
- }
- if (range_stop > total) {
- range_stop = total;
- }
- spager = _.str.sprintf(_t("%d-%d of %d"), range_start, range_stop, total);
- }
+ $column.siblings('.o_column_sortable').removeClass("o-sort-up o-sort-down");
- this.$pager.find('.oe_list_pager_state').text(spager);
- }
- }
+ return this.reload_content();
},
/**
* Sets up the listview's columns: merges view and fields data, move
@@ -422,8 +376,7 @@ var ListView = View.extend({
return for_(id, fields[id], field);
}));
if (grouped) {
- this.columns.unshift(
- new ListView.MetaColumn('_group', _t("Group")));
+ this.columns.unshift(new ListView.MetaColumn('_group'));
}
this.visible_columns = _.filter(this.columns, function (column) {
@@ -468,27 +421,27 @@ var ListView = View.extend({
*/
reload_content: synchronized(function () {
var self = this;
- self.$el.find('.oe_list_record_selector').prop('checked', false);
+ this.setup_columns(this.fields_view.fields, this.grouped);
+ this.$('tbody .o_list_record_selector input').prop('checked', false);
this.records.reset();
var reloaded = $.Deferred();
- reloaded.then(function () {
- self.configure_pager(self.dataset);
- });
- this.$el.find('.oe_list_content').append(
- this.groups.render(function () {
- if (self.dataset.index === null) {
- if (self.records.length) {
- self.dataset.index = 0;
- }
- } else if (self.dataset.index >= self.records.length) {
- self.dataset.index = self.records.length ? 0 : null;
+ this.groups.render(function () {
+ if (self.dataset.index === null) {
+ if (self.records.length) {
+ self.dataset.index = 0;
+ }
+ } else if (self.dataset.index >= self.records.length) {
+ self.dataset.index = self.records.length ? 0 : null;
+ }
+ self.load_list().then(function () {
+ if (!self.grouped && self.display_nocontent_helper()) {
+ self.no_result();
}
-
- self.compute_aggregates();
reloaded.resolve();
- }));
+ });
+ });
this.do_push_state({
- page: this.page,
+ min: this.current_min,
limit: this._limit
});
return reloaded.promise();
@@ -531,8 +484,8 @@ var ListView = View.extend({
do_load_state: function(state, warm) {
var reload = false;
- if (state.page && this.page !== state.page) {
- this.page = state.page;
+ if (state.min && this.current_min !== state.min) {
+ this.current_min = state.min;
reload = true;
}
if (state.limit) {
@@ -558,7 +511,7 @@ var ListView = View.extend({
* @param {Object} results results of evaluating domain and process for a search
*/
do_search: function (domain, context, group_by) {
- this.page = 0;
+ this.current_min = 1;
this.groups.datagroup = new DataGroup(
this, this.model, domain, context, group_by);
this.groups.datagroup.sort = this.dataset._sort;
@@ -569,6 +522,10 @@ var ListView = View.extend({
this.no_leaf = !!context['group_by_no_leaf'];
this.grouped = !!group_by;
+ // Hide the pager in grouped mode
+ if (this.pager && this.grouped) {
+ this.pager.do_hide();
+ }
return this.reload_content();
},
/**
@@ -581,26 +538,25 @@ var ListView = View.extend({
return;
}
var self = this;
+
return $.when(this.dataset.unlink(ids)).done(function () {
_(ids).each(function (id) {
self.records.remove(self.records.get(id));
});
// Hide the table if there is no more record in the dataset
- if (self.dataset.size() === 0) {
+ if (self.display_nocontent_helper()) {
self.no_result();
} else {
+ // Load previous page if the current one is empty
if (self.records.length === 0 && self.dataset.size() > 0) {
- //Trigger previous manually to navigate to previous page,
- //If all records are deleted on current page.
- self.$pager.find('ul li:first a').trigger('click');
- } else if (self.dataset.size() === self._limit) {
- //Reload listview to update current page with next page records
- //because pager going to be hidden if dataset.size == limit
+ self.pager.previous();
+ }
+ // Reload the list view if we are not on the last page
+ if (self.current_min + self._limit - 1 < self.dataset.size()) {
self.reload();
- } else {
- self.configure_pager(self.dataset);
}
}
+ self.update_pager(self.dataset);
self.compute_aggregates();
});
},
@@ -613,7 +569,7 @@ var ListView = View.extend({
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);
+ this.$('thead .o_list_record_selector input').prop('checked', false);
}
if (!ids.length) {
@@ -810,13 +766,14 @@ var ListView = View.extend({
this.display_aggregates(aggregates);
},
display_aggregates: function (aggregation) {
- var $footer_cells = this.$el.find('.oe_list_footer');
+ var $footer_cells = this.$('tfoot td');
_(this.aggregate_columns).each(function (column) {
if (!column['function']) {
return;
}
$footer_cells.filter(_.str.sprintf('[data-field=%s]', column.id))
+ .addClass('o_list_number')
.html(column.format(aggregation, { process_modifiers: false }));
});
},
@@ -831,7 +788,7 @@ var ListView = View.extend({
*/
get_active_domain: function () {
var self = this;
- if (this.$('.oe_list_record_selector').prop('checked')) {
+ if (this.$('thead .o_list_record_selector input').prop('checked')) {
var search_view = this.getParent().searchview;
var search_data = search_view.build_search_data();
return pyeval.eval_domains_and_contexts({
@@ -859,7 +816,7 @@ var ListView = View.extend({
pad_columns: function (count, options) {
options = options || {};
// padding for action/pager header
- var $first_header = this.$el.find('thead tr:first th');
+ var $first_header = this.$('thead tr:first th');
var colspan = $first_header.attr('colspan');
if (colspan) {
if (!this.previous_colspan) {
@@ -882,7 +839,7 @@ var ListView = View.extend({
* Removes all padding columns of the table
*/
unpad_columns: function () {
- this.$el.find('.oe_list_padding').remove();
+ this.$('.oe_list_padding').remove();
if (this.previous_colspan) {
this.$el
.find('thead tr:first th')
@@ -890,23 +847,20 @@ var ListView = View.extend({
this.previous_colspan = null;
}
},
+ display_nocontent_helper: function () {
+ return (this.dataset.size() === 0);
+ },
no_result: function () {
- this.$el.find('.oe_view_nocontent').remove();
- if (this.groups.group_by
- || !this.options.action
- || !this.options.action.help) {
+ this.$('.oe_view_nocontent').remove();
+ if (this.groups.group_by ||
+ !this.options.action ||
+ !this.options.action.help) {
return;
}
- this.$el.find('table:first').hide();
+ this.$('table:first').hide();
this.$el.prepend(
$('<div class="oe_view_nocontent">').html(this.options.action.help)
);
- if (this.$buttons) {
- var $buttons = this.$buttons;
- this.$el.find('.oe_view_nocontent').click(function() {
- $buttons.width($buttons.width() + 1).openerpBounce();
- });
- }
}
});
core.view_registry.add('list', ListView);
@@ -975,9 +929,8 @@ ListView.List = Class.extend({
$row = self.$current.children(
'[data-id=' + record.get('id') + ']');
}
-
var $newRow = $(self.render_record(record));
- $newRow.find('.oe_list_record_selector input').prop('checked', !!$row.find('.oe_list_record_selector input').prop('checked'));
+ $newRow.find('.o_list_record_selector input').prop('checked', !!$row.find('.o_list_record_selector input').prop('checked'));
$row.replaceWith($newRow);
},
'add': function (ev, records, record, index) {
@@ -1012,14 +965,14 @@ ListView.List = Class.extend({
*/
e.preventDefault();
})
- .delegate('th.oe_list_record_selector', 'click', function (e) {
+ .delegate('td.o_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, ! checked]);
})
- .delegate('td.oe_list_record_delete', 'click', function (e) {
+ .delegate('td.o_list_record_delete', 'click', function (e) {
e.stopPropagation();
var $row = $(e.target).closest('tr');
$(self).trigger('deleted', [[self.row_id($row)]]);
@@ -1028,7 +981,7 @@ ListView.List = Class.extend({
$('<input />').appendTo('body').focus().remove();
}
})
- .delegate('td.oe_list_field_cell button', 'click', function (e) {
+ .delegate('td button', 'click', function (e) {
e.stopPropagation();
var $target = $(e.currentTarget),
field = $target.closest('td').data('field'),
@@ -1158,7 +1111,7 @@ ListView.List = Class.extend({
}
var cells = [];
if (this.options.selectable) {
- cells.push('<th class="oe_list_record_selector"></td>');
+ cells.push('<td class="o_list_record_selector"></td>');
}
_(this.columns).each(function(column) {
if (column.invisible === '1') {
@@ -1167,7 +1120,7 @@ ListView.List = Class.extend({
cells.push('<td title="' + column.string + '">&nbsp;</td>');
});
if (this.options.deletable) {
- cells.push('<td class="oe_list_record_delete"></td>');
+ cells.push('<td class="o_list_record_delete"></td>');
}
cells.unshift('<tr>');
cells.push('</tr>');
@@ -1187,7 +1140,7 @@ ListView.List = Class.extend({
return result;
}
var records = this.records;
- this.$current.find('th.oe_list_record_selector input:checked')
+ this.$current.find('td.o_list_record_selector input:checked')
.closest('tr').each(function () {
var record = records.get($(this).data('id'));
result.ids.push(record.get('id'));
@@ -1206,14 +1159,12 @@ ListView.List = Class.extend({
return $(row).data('id');
},
/**
- * Death signal, cleans up list display
+ * Death signal, cleans up records's callbacks
*/
on_records_reset: function () {
_(this.record_callbacks).each(function (callback, event) {
this.records.unbind(event, callback);
}, this);
- if (!this.$current) { return; }
- this.$current.remove();
},
get_records: function () {
return this.records.map(function (record) {
@@ -1279,7 +1230,7 @@ ListView.Groups = Class.extend({
this.$row = null;
this.children = {};
- this.page = 0;
+ this.pager = null; // group pager
var self = this;
this.records.bind('reset', function () {
@@ -1315,51 +1266,46 @@ ListView.Groups = Class.extend({
}
return red_letter_tboday;
},
- make_paginator: function () {
+ /**
+ * Renders the group pager and append it to the group's header
+ */
+ render_group_pager: function () {
var self = this;
- var $prev = $('<button type="button" data-pager-action="previous">&lt;</button>')
- .click(function (e) {
- e.stopPropagation();
- if (self.page > 0) {
- self.page -= 1;
- } else {
- self.page = self.max_page_index;
- }
-
- self.$row.closest('tbody').next()
- .replaceWith(self.render());
+ if (this.datagroup.length > this.view._limit) {
+ this.pager = new Pager(this, this.datagroup.length, 1, this.view._limit);
+ this.pager.on('pager_changed', this, function (state) {
+ self.view._limit = state.limit;
+ self.current_min = state.current_min;
+ self.render().then(function() {
+ self.$row.closest('tbody').next().replaceWith($(self.elements));
+ });
});
- var $next = $('<button type="button" data-pager-action="next">&gt;</button>')
- .click(function (e) {
- e.stopPropagation();
- if (self.page < self.max_page_index) {
- self.page += 1;
- } else {
- self.page = 0;
- }
- self.$row.closest('tbody').next()
- .replaceWith(self.render());
+ var $last_cell = this.$row.children().last();
+ $last_cell.addClass('o_group_pager');
+ // Prevent group to fold when clicking on the pager
+ $last_cell.click(function(e) {
+ e.stopPropagation();
});
- this.$row.children().last()
- .addClass('oe_list_group_pagination')
- .append($prev)
- .append('<span class="oe_list_pager_state"></span>')
- .append($next);
+ this.pager.appendTo($last_cell);
+ }
},
open: function (point_insertion) {
- this.render().insertAfter(point_insertion);
+ this.render();
+ $(this.elements).insertAfter(point_insertion);
var no_subgroups = _(this.datagroup.group_by).isEmpty(),
records_terminated = !this.datagroup.context['group_by_no_leaf'];
if (no_subgroups && records_terminated) {
- this.make_paginator();
+ this.render_group_pager();
}
},
close: function () {
- this.$row.children().last().find('button').remove();
- this.$row.children().last().find('span').remove();
+ if (this.pager) {
+ this.pager.destroy();
+ }
this.records.reset();
+ this.$to_be_removed.remove();
},
/**
* Prefixes ``$node`` with floated spaces in order to indent it relative
@@ -1391,20 +1337,20 @@ ListView.Groups = Class.extend({
self.bind_child_events(child);
child.datagroup = group;
- var $row = child.$row = $('<tr class="oe_group_header">');
+ var $row = child.$row = $('<tr class="o_group_header">');
if (group.openable && group.length) {
$row.click(function (e) {
if (!$row.data('open')) {
$row.data('open', true)
- .find('span.ui-icon')
- .removeClass('ui-icon-triangle-1-e')
- .addClass('ui-icon-triangle-1-s');
+ .find('span.fa')
+ .removeClass('fa-caret-right')
+ .addClass('fa-caret-down');
child.open(self.point_insertion(e.currentTarget));
} else {
$row.removeData('open')
- .find('span.ui-icon')
- .removeClass('ui-icon-triangle-1-s')
- .addClass('ui-icon-triangle-1-e');
+ .find('span.fa')
+ .removeClass('fa-caret-down')
+ .addClass('fa-caret-right');
child.close();
// force recompute the selection as closing group reset properties
var selection = self.get_selection();
@@ -1414,7 +1360,7 @@ ListView.Groups = Class.extend({
}
placeholder.appendChild($row[0]);
- var $group_column = $('<th class="oe_list_group_name">').appendTo($row);
+ var $group_column = $('<th class="o_group_name">').appendTo($row);
// Don't fill this if group_by_no_leaf but no group_by
if (group.grouped_on) {
var row_data = {};
@@ -1449,12 +1395,9 @@ ListView.Groups = Class.extend({
if (group.length && group.openable) {
// Make openable if not terminal group & group_by_no_leaf
- $group_column.prepend('<span class="ui-icon ui-icon-triangle-1-e" style="float: left;">');
+ $group_column.prepend('<span class="fa fa-caret-right" style="padding-right: 5px;">');
} else {
- // Kinda-ugly hack: jquery-ui has no "empty" icon, so set
- // wonky background position to ensure nothing is displayed
- // there but the rest of the behavior is ui-icon's
- $group_column.prepend('<span class="ui-icon" style="float: left; background-position: 150px 150px">');
+ $group_column.prepend('<span class="fa">');
}
}
self.indent($group_column, group.level);
@@ -1511,13 +1454,11 @@ ListView.Groups = Class.extend({
});
this.bind_child_events(list);
- var view = this.view,
- limit = view._limit,
- page = this.datagroup.openable ? this.page : view.page;
+ var view = this.view;
+ var current_min = this.datagroup.openable ? this.current_min : view.current_min;
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
+ var options = { offset: current_min - 1, limit: view._limit, context: {bin_size: true} };
return $.async_when().then(function() {
return dataset.read_slice(fields, options).then(function (records) {
// FIXME: ignominious hacks, parents (aka form view) should not send two ListView#reload_content concurrently
@@ -1525,34 +1466,12 @@ ListView.Groups = Class.extend({
self.records.reset(null, {silent: true});
}
if (!self.datagroup.openable) {
- view.configure_pager(dataset);
- } else {
- if (dataset.size() == records.length) {
- // only one page
- self.$row.find('td.oe_list_group_pagination').find('button').remove();
- self.$row.find('td.oe_list_group_pagination').find('span').remove();
- } else {
- self.max_page_index = Math.ceil(dataset.size() / limit) - 1;
- self.$row
- .find('.oe_list_pager_state')
- .text(_.str.sprintf(_t("%(page)d/%(page_count)d"), {
- page: page + 1,
- page_count: self.max_page_index + 1
- }))
- .end()
- .find('button[data-pager-action=previous]')
- .toggleClass('disabled', page === 0)
- .end()
- .find('button[data-pager-action=next]')
- .toggleClass('disabled', page === self.max_page_index);
- }
+ // Update the main list view pager
+ view.update_pager(dataset, current_min);
}
self.records.add(records, {silent: true});
list.render();
- if (_.isEmpty(records)) {
- view.no_result();
- }
return list;
});
});
@@ -1580,7 +1499,7 @@ ListView.Groups = Class.extend({
helper: 'clone'
});
if (sequence_field) {
- list.$current.sortable('option', 'handle', '.oe_list_field_handle');
+ list.$current.sortable('option', 'handle', '.o_row_handle');
}
list.$current.sortable('option', {
start: function (e, ui) {
@@ -1631,7 +1550,7 @@ ListView.Groups = Class.extend({
var $el = $('<tbody>');
this.elements = [$el[0]];
- this.datagroup.list(
+ return this.datagroup.list(
_(this.view.visible_columns).chain()
.filter(function (column) { return column.tag === 'field';})
.pluck('name').value(),
@@ -1640,7 +1559,7 @@ ListView.Groups = Class.extend({
self.render_groups(groups));
if (post_render) { post_render(); }
}, function (dataset) {
- self.render_dataset(dataset).then(function (list) {
+ return self.render_dataset(dataset).then(function (list) {
self.children[null] = list;
self.elements =
[list.$current.replaceAll($el)[0]];
@@ -1650,7 +1569,6 @@ ListView.Groups = Class.extend({
self.view.trigger('view_list_rendered');
});
});
- return $el;
},
/**
* Returns the ids of all selected records for this group, and the records
@@ -1669,8 +1587,11 @@ ListView.Groups = Class.extend({
return {ids: ids, records: records};
},
on_records_reset: function () {
+ this.$to_be_removed = $(this.elements);
+ _.each(this.children, function(child){
+ this.$to_be_removed = this.$to_be_removed.add(child.$to_be_removed);
+ }.bind(this));
this.children = {};
- $(this.elements).remove();
},
get_records: function () {
if (_(this.children).isEmpty()) {
@@ -1725,13 +1646,12 @@ var DataGroup = Class.extend({
fields = _.unique((fields || []).concat(this.group_by));
}
var query = this.model.query(fields).order_by(this.sort).group_by(this.group_by);
- $.when(query).done(function (querygroups) {
+ return $.when(query).then(function (querygroups) {
// leaf node
if (!querygroups) {
var ds = new data.DataSetSearch(self, self.model.name, self.model.context(), self.model.domain());
ds._sort = self.sort;
- ifRecords(ds);
- return;
+ return ifRecords(ds);
}
// internal node
var child_datagroups = _(querygroups).map(function (group) {
@@ -1763,7 +1683,7 @@ var StaticDataGroup = DataGroup.extend({
this.dataset = dataset;
},
list: function (fields, ifGroups, ifRecords) {
- ifRecords(this.dataset);
+ return ifRecords(this.dataset);
}
});
@@ -1811,6 +1731,10 @@ var Column = Class.extend({
C.prototype = this;
return new C(aggregation_func, this[aggregation_func]);
},
+ heading: function () {
+ return _.escape(this.string);
+ },
+ width: function () {},
/**
*
* @param row_data record whose values should be displayed in the cell
@@ -1834,7 +1758,8 @@ var Column = Class.extend({
? ''
: options.value_if_empty;
}
- return this._format(row_data, options);
+ var f = this._format(row_data, options);
+ return (f !== '')? f : '&nbsp;';
},
/**
* Method to override in order to provide alternative HTML content for the
@@ -1890,7 +1815,7 @@ var ColumnBoolean = Column.extend({
* @private
*/
_format: function (row_data, options) {
- return _.str.sprintf('<input type="checkbox" %s readonly="readonly"/>',
+ return _.str.sprintf('<div class="o_checkbox"><input type="checkbox" %s disabled="disabled"/><span/></div>',
row_data[this.id].value ? 'checked="checked"' : '');
}
});
@@ -1965,14 +1890,19 @@ var ColumnHandle = Column.extend({
this._super.apply(this, arguments);
// Handle overrides the field to not be form-editable.
this.modifiers.readonly = true;
+ this.string = ""; // Don't display the column header
+ },
+ heading: function () {
+ return '<span class="o_row_handle fa fa-arrows invisible"></span>';
},
+ width: function () { return 1; },
/**
* Return styling hooks for a drag handle
*
* @private
*/
_format: function (row_data, options) {
- return '<i class="oe_list_handle fa fa-circle"/>';
+ return '<span class="o_row_handle fa fa-arrows"/>';
}
});
@@ -2042,8 +1972,9 @@ var ColumnUrl = Column.extend({
var ColumnMonetary = Column.extend({
_format: function (row_data, options) {
+ var options = pyeval.py_eval(this.options || '{}');
//name of currency field is defined either by field attribute, in view options or we assume it is named currency_id
- var currency_field = (this.options && this.options.currency_field) || this.currency_field || 'currency_id';
+ var currency_field = (_.isEmpty(options) === false && options.currency_field) || this.currency_field || 'currency_id';
var currency_id = row_data[currency_field] && row_data[currency_field].value[0];
var currency = session.get_currency(currency_id);
var digits_precision = this.digits || (currency && currency.digits);